QGIS API Documentation  2.14.0-Essen
qgsgml.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgml.cpp
3  ---------------------
4  begin : February 2013
5  copyright : (C) 2013 by Radim Blazek
6  email : radim dot blazek at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include "qgsgml.h"
16 #include "qgsauthmanager.h"
17 #include "qgsrectangle.h"
19 #include "qgsgeometry.h"
20 #include "qgslogger.h"
21 #include "qgsmessagelog.h"
23 #include "qgswkbptr.h"
24 
25 #include <QBuffer>
26 #include <QList>
27 #include <QNetworkRequest>
28 #include <QNetworkReply>
29 #include <QProgressDialog>
30 #include <QSet>
31 #include <QSettings>
32 #include <QUrl>
33 
34 #include <limits>
35 
36 const char NS_SEPARATOR = '?';
37 const QString GML_NAMESPACE = "http://www.opengis.net/gml";
38 
40  const QString& typeName,
41  const QString& geometryAttribute,
42  const QgsFields & fields )
43  : QObject()
44  , mTypeName( typeName )
45  , mGeometryAttribute( geometryAttribute )
46  , mWkbType( nullptr )
47  , mFinished( false )
48  , mCurrentFeature( nullptr )
49  , mFeatureCount( 0 )
50  , mCurrentWKB( nullptr, 0 )
51  , mDimension( 2 )
52  , mCoorMode( QgsGml::coordinate )
53  , mEpsg( 0 )
54 {
55  mThematicAttributes.clear();
56  for ( int i = 0; i < fields.size(); i++ )
57  {
58  mThematicAttributes.insert( fields[i].name(), qMakePair( i, fields[i] ) );
59  }
60 
61  mEndian = QgsApplication::endian();
62 
63  int index = mTypeName.indexOf( ':' );
64  if ( index != -1 && index < mTypeName.length() )
65  {
66  mTypeName = mTypeName.mid( index + 1 );
67  }
68 }
69 
71 {
72 }
73 
74 int QgsGml::getFeatures( const QString& uri, QGis::WkbType* wkbType, QgsRectangle* extent, const QString& userName, const QString& password , const QString& authcfg )
75 {
76  mUri = uri;
77  mWkbType = wkbType;
78 
79  XML_Parser p = XML_ParserCreateNS( nullptr, NS_SEPARATOR );
80  XML_SetUserData( p, this );
81  XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
82  XML_SetCharacterDataHandler( p, QgsGml::chars );
83 
84  //start with empty extent
85  mExtent.setMinimal();
86 
87  QNetworkRequest request( mUri );
88  if ( !authcfg.isEmpty() )
89  {
90  if ( !QgsAuthManager::instance()->updateNetworkRequest( request, authcfg ) )
91  {
93  tr( "GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
94  tr( "Network" ),
96  );
97  return 1;
98  }
99  }
100  else if ( !userName.isNull() || !password.isNull() )
101  {
102  request.setRawHeader( "Authorization", "Basic " + QString( "%1:%2" ).arg( userName, password ).toAscii().toBase64() );
103  }
104  QNetworkReply* reply = QgsNetworkAccessManager::instance()->get( request );
105 
106  connect( reply, SIGNAL( finished() ), this, SLOT( setFinished() ) );
107  connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( handleProgressEvent( qint64, qint64 ) ) );
108 
109  //find out if there is a QGIS main window. If yes, display a progress dialog
110  QProgressDialog* progressDialog = nullptr;
111  QWidget* mainWindow = nullptr;
112  QWidgetList topLevelWidgets = qApp->topLevelWidgets();
113  for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
114  {
115  if (( *it )->objectName() == "QgisApp" )
116  {
117  mainWindow = *it;
118  break;
119  }
120  }
121  if ( mainWindow )
122  {
123  progressDialog = new QProgressDialog( tr( "Loading GML data\n%1" ).arg( mTypeName ), tr( "Abort" ), 0, 0, mainWindow );
124  progressDialog->setWindowModality( Qt::ApplicationModal );
125  connect( this, SIGNAL( dataReadProgress( int ) ), progressDialog, SLOT( setValue( int ) ) );
126  connect( this, SIGNAL( totalStepsUpdate( int ) ), progressDialog, SLOT( setMaximum( int ) ) );
127  connect( progressDialog, SIGNAL( canceled() ), this, SLOT( setFinished() ) );
128  progressDialog->show();
129  }
130 
131  int atEnd = 0;
132  while ( !atEnd )
133  {
134  if ( mFinished )
135  {
136  atEnd = 1;
137  }
138  QByteArray readData = reply->readAll();
139  if ( !readData.isEmpty() )
140  {
141  if ( XML_Parse( p, readData.constData(), readData.size(), atEnd ) == 0 )
142  {
143  XML_Error errorCode = XML_GetErrorCode( p );
144  QString errorString = tr( "Error: %1 on line %2, column %3" )
145  .arg( XML_ErrorString( errorCode ) )
146  .arg( XML_GetCurrentLineNumber( p ) )
147  .arg( XML_GetCurrentColumnNumber( p ) );
148  QgsMessageLog::logMessage( errorString, tr( "WFS" ) );
149  }
150  }
152  }
153 
154  QNetworkReply::NetworkError replyError = reply->error();
155  QString replyErrorString = reply->errorString();
156 
157  delete reply;
158  delete progressDialog;
159 
160  if ( replyError )
161  {
163  tr( "GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
164  tr( "Network" ),
166  );
167  return 1;
168  }
169 
170  if ( *mWkbType != QGis::WKBNoGeometry )
171  {
172  if ( mExtent.isEmpty() )
173  {
174  //reading of bbox from the server failed, so we calculate it less efficiently by evaluating the features
175  calculateExtentFromFeatures();
176  }
177  }
178 
179  XML_ParserFree( p );
180 
181  if ( extent )
182  *extent = mExtent;
183 
184  return 0;
185 }
186 
187 int QgsGml::getFeatures( const QByteArray &data, QGis::WkbType* wkbType, QgsRectangle* extent )
188 {
189  mWkbType = wkbType;
190  mExtent.setMinimal();
191 
192  XML_Parser p = XML_ParserCreateNS( nullptr, NS_SEPARATOR );
193  XML_SetUserData( p, this );
194  XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
195  XML_SetCharacterDataHandler( p, QgsGml::chars );
196  int atEnd = 1;
197  XML_Parse( p, data.constData(), data.size(), atEnd );
198 
199  if ( extent )
200  *extent = mExtent;
201 
202  return 0;
203 }
204 
205 void QgsGml::setFinished()
206 {
207  mFinished = true;
208 }
209 
210 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
211 {
212  if ( totalSteps < 0 )
213  {
214  totalSteps = 0;
215  progress = 0;
216  }
217  emit totalStepsUpdate( totalSteps );
218  emit dataReadProgress( progress );
219  emit dataProgressAndSteps( progress, totalSteps );
220 }
221 
222 void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
223 {
224  QString elementName( QString::fromUtf8( el ) );
225  ParseMode theParseMode( mParseModeStack.isEmpty() ? none : mParseModeStack.top() );
226  QStringList splitName = elementName.split( NS_SEPARATOR );
227  QString localName = splitName.last();
228  QString ns = splitName.size() > 1 ? splitName.first() : "";
229 
230  if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
231  {
232  mParseModeStack.push( QgsGml::coordinate );
233  mCoorMode = QgsGml::coordinate;
234  mStringCash.clear();
235  mCoordinateSeparator = readAttribute( "cs", attr );
236  if ( mCoordinateSeparator.isEmpty() )
237  {
238  mCoordinateSeparator = ',';
239  }
240  mTupleSeparator = readAttribute( "ts", attr );
241  if ( mTupleSeparator.isEmpty() )
242  {
243  mTupleSeparator = ' ';
244  }
245  }
246  if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "pos"
247  || elementName == GML_NAMESPACE + NS_SEPARATOR + "posList" )
248  {
249  mParseModeStack.push( QgsGml::posList );
250  mCoorMode = QgsGml::posList;
251  mStringCash.clear();
252  QString dimension = readAttribute( "srsDimension", attr );
253  bool ok;
254  mDimension = dimension.toInt( &ok );
255  if ( dimension.isEmpty() || !ok )
256  {
257  mDimension = 2;
258  }
259  }
260  else if ( localName == mGeometryAttribute )
261  {
262  mParseModeStack.push( QgsGml::geometry );
263  }
264  //else if ( mParseModeStack.size() == 0 && elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
265  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
266  {
267  mParseModeStack.push( QgsGml::boundingBox );
268  }
269  else if ( theParseMode == none && localName == mTypeName )
270  {
271  Q_ASSERT( !mCurrentFeature );
272  mCurrentFeature = new QgsFeature( mFeatureCount );
273  QgsAttributes attributes( mThematicAttributes.size() ); //add empty attributes
274  mCurrentFeature->setAttributes( attributes );
275  mParseModeStack.push( QgsGml::feature );
276  mCurrentFeatureId = readAttribute( "fid", attr );
277  }
278 
279  else if ( theParseMode == boundingBox && elementName == GML_NAMESPACE + NS_SEPARATOR + "Box" )
280  {
281  //read attribute srsName="EPSG:26910"
282  int epsgNr;
283  if ( readEpsgFromAttribute( epsgNr, attr ) != 0 )
284  {
285  QgsDebugMsg( "error, could not get epsg id" );
286  }
287  }
288  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
289  {
290  mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
291  }
292  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPoint" )
293  {
294  mParseModeStack.push( QgsGml::multiPoint );
295  //we need one nested list for intermediate WKB
296  mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
297  }
298  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiLineString" )
299  {
300  mParseModeStack.push( QgsGml::multiLine );
301  //we need one nested list for intermediate WKB
302  mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
303  }
304  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPolygon" )
305  {
306  mParseModeStack.push( QgsGml::multiPolygon );
307  }
308  else if ( theParseMode == feature && mThematicAttributes.contains( localName ) )
309  {
310  mParseModeStack.push( QgsGml::attribute );
311  mAttributeName = localName;
312  mStringCash.clear();
313  }
314  // QGIS server (2.2) is using:
315  // <Attribute value="My description" name="desc"/>
316  else if ( theParseMode == feature
317  && localName.compare( "attribute", Qt::CaseInsensitive ) == 0 )
318  {
319  QString name = readAttribute( "name", attr );
320  if ( mThematicAttributes.contains( name ) )
321  {
322  QString value = readAttribute( "value", attr );
323  setAttribute( name, value );
324  }
325  }
326 
327  if ( mEpsg == 0 && ( localName == "Point" || localName == "MultiPoint" ||
328  localName == "LineString" || localName == "MultiLineString" ||
329  localName == "Polygon" || localName == "MultiPolygon" ) )
330  {
331  if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
332  {
333  QgsDebugMsg( "error, could not get epsg id" );
334  }
335  else
336  {
337  QgsDebugMsg( QString( "mEpsg = %1" ).arg( mEpsg ) );
338  }
339  }
340 }
341 
342 void QgsGml::endElement( const XML_Char* el )
343 {
344  QString elementName( QString::fromUtf8( el ) );
345  ParseMode theParseMode( mParseModeStack.isEmpty() ? none : mParseModeStack.top() );
346  QStringList splitName = elementName.split( NS_SEPARATOR );
347  QString localName = splitName.last();
348  QString ns = splitName.size() > 1 ? splitName.first() : "";
349 
350  if (( theParseMode == coordinate && elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
351  || ( theParseMode == posList && (
352  elementName == GML_NAMESPACE + NS_SEPARATOR + "pos"
353  || elementName == GML_NAMESPACE + NS_SEPARATOR + "posList" ) ) )
354  {
355  mParseModeStack.pop();
356  }
357  else if ( theParseMode == attribute && localName == mAttributeName ) //add a thematic attribute to the feature
358  {
359  mParseModeStack.pop();
360 
361  setAttribute( mAttributeName, mStringCash );
362  }
363  else if ( theParseMode == geometry && localName == mGeometryAttribute )
364  {
365  mParseModeStack.pop();
366  }
367  else if ( theParseMode == boundingBox && elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
368  {
369  //create bounding box from mStringCash
370  if ( createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) != 0 )
371  {
372  QgsDebugMsg( "creation of bounding box failed" );
373  }
374 
375  mParseModeStack.pop();
376  }
377  else if ( theParseMode == feature && localName == mTypeName )
378  {
379  Q_ASSERT( mCurrentFeature );
380  if ( mCurrentWKB.size() > 0 )
381  {
382  QgsGeometry *g = new QgsGeometry();
383  g->fromWkb( mCurrentWKB, mCurrentWKB.size() );
384  mCurrentFeature->setGeometry( g );
385  mCurrentWKB = QgsWkbPtr( nullptr, 0 );
386  }
387  else if ( !mCurrentExtent.isEmpty() )
388  {
389  mCurrentFeature->setGeometry( QgsGeometry::fromRect( mCurrentExtent ) );
390  }
391  else
392  {
393  mCurrentFeature->setGeometry( nullptr );
394  }
395  mCurrentFeature->setValid( true );
396 
397  mFeatures.insert( mCurrentFeature->id(), mCurrentFeature );
398  if ( !mCurrentFeatureId.isEmpty() )
399  {
400  mIdMap.insert( mCurrentFeature->id(), mCurrentFeatureId );
401  }
402  mCurrentFeature = nullptr;
403  ++mFeatureCount;
404  mParseModeStack.pop();
405  }
406  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Point" )
407  {
408  QList<QgsPoint> pointList;
409  if ( pointsFromString( pointList, mStringCash ) != 0 )
410  {
411  //error
412  }
413 
414  if ( pointList.isEmpty() )
415  return; // error
416 
417  if ( theParseMode == QgsGml::geometry )
418  {
419  //directly add WKB point to the feature
420  if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
421  {
422  //error
423  }
424 
425  if ( *mWkbType != QGis::WKBMultiPoint ) //keep multitype in case of geometry type mix
426  {
427  *mWkbType = QGis::WKBPoint;
428  }
429  }
430  else //multipoint, add WKB as fragment
431  {
432  QgsWkbPtr wkbPtr( nullptr, 0 );
433  if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
434  {
435  //error
436  }
437  if ( !mCurrentWKBFragments.isEmpty() )
438  {
439  mCurrentWKBFragments.last().push_back( wkbPtr );
440  }
441  else
442  {
443  QgsDebugMsg( "No wkb fragments" );
444  delete [] wkbPtr;
445  }
446  }
447  }
448  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "LineString" )
449  {
450  //add WKB point to the feature
451 
452  QList<QgsPoint> pointList;
453  if ( pointsFromString( pointList, mStringCash ) != 0 )
454  {
455  //error
456  }
457  if ( theParseMode == QgsGml::geometry )
458  {
459  if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
460  {
461  //error
462  }
463 
464  if ( *mWkbType != QGis::WKBMultiLineString )//keep multitype in case of geometry type mix
465  {
466  *mWkbType = QGis::WKBLineString;
467  }
468  }
469  else //multiline, add WKB as fragment
470  {
471  QgsWkbPtr wkbPtr( nullptr, 0 );
472  if ( getLineWKB( wkbPtr, pointList ) != 0 )
473  {
474  //error
475  }
476  if ( !mCurrentWKBFragments.isEmpty() )
477  {
478  mCurrentWKBFragments.last().push_back( wkbPtr );
479  }
480  else
481  {
482  QgsDebugMsg( "no wkb fragments" );
483  delete [] wkbPtr;
484  }
485  }
486  }
487  else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE + NS_SEPARATOR + "LinearRing" )
488  {
489  QList<QgsPoint> pointList;
490  if ( pointsFromString( pointList, mStringCash ) != 0 )
491  {
492  //error
493  }
494 
495  QgsWkbPtr wkbPtr( nullptr, 0 );
496  if ( getRingWKB( wkbPtr, pointList ) != 0 )
497  {
498  //error
499  }
500 
501  if ( !mCurrentWKBFragments.isEmpty() )
502  {
503  mCurrentWKBFragments.last().push_back( wkbPtr );
504  }
505  else
506  {
507  delete[] wkbPtr;
508  QgsDebugMsg( "no wkb fragments" );
509  }
510  }
511  else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
512  {
513  if ( *mWkbType != QGis::WKBMultiPolygon )//keep multitype in case of geometry type mix
514  {
515  *mWkbType = QGis::WKBPolygon;
516  }
517 
518  if ( theParseMode == geometry )
519  {
520  createPolygonFromFragments();
521  }
522  }
523  else if ( theParseMode == multiPoint && elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPoint" )
524  {
525  *mWkbType = QGis::WKBMultiPoint;
526  mParseModeStack.pop();
527  createMultiPointFromFragments();
528  }
529  else if ( theParseMode == multiLine && elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiLineString" )
530  {
531  *mWkbType = QGis::WKBMultiLineString;
532  mParseModeStack.pop();
533  createMultiLineFromFragments();
534  }
535  else if ( theParseMode == multiPolygon && elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPolygon" )
536  {
537  *mWkbType = QGis::WKBMultiPolygon;
538  mParseModeStack.pop();
539  createMultiPolygonFromFragments();
540  }
541 }
542 
543 void QgsGml::characters( const XML_Char* chars, int len )
544 {
545  //save chars in mStringCash attribute mode or coordinate mode
546  if ( mParseModeStack.isEmpty() )
547  {
548  return;
549  }
550 
551  QgsGml::ParseMode theParseMode = mParseModeStack.top();
552  if ( theParseMode == QgsGml::attribute || theParseMode == QgsGml::coordinate || theParseMode == QgsGml::posList )
553  {
554  mStringCash.append( QString::fromUtf8( chars, len ) );
555  }
556 }
557 
558 void QgsGml::setAttribute( const QString& name, const QString& value )
559 {
560  //find index with attribute name
561  QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
562  if ( att_it != mThematicAttributes.constEnd() )
563  {
564  QVariant var;
565  switch ( att_it.value().second.type() )
566  {
567  case QVariant::Double:
568  var = QVariant( value.toDouble() );
569  break;
570  case QVariant::Int:
571  var = QVariant( value.toInt() );
572  break;
573  case QVariant::LongLong:
574  var = QVariant( value.toLongLong() );
575  break;
576  default: //string type is default
577  var = QVariant( value );
578  break;
579  }
580  Q_ASSERT( mCurrentFeature );
581  mCurrentFeature->setAttribute( att_it.value().first, var );
582  }
583 }
584 
585 int QgsGml::readEpsgFromAttribute( int& epsgNr, const XML_Char** attr ) const
586 {
587  int i = 0;
588  while ( attr[i] )
589  {
590  if ( strcmp( attr[i], "srsName" ) == 0 )
591  {
592  QString epsgString( attr[i+1] );
593  QString epsgNrString;
594  if ( epsgString.startsWith( "http" ) ) //e.g. geoserver: "http://www.opengis.net/gml/srs/epsg.xml#4326"
595  {
596  epsgNrString = epsgString.section( '#', 1, 1 );
597  }
598  else //e.g. umn mapserver: "EPSG:4326">
599  {
600  epsgNrString = epsgString.section( ':', 1, 1 );
601  }
602  bool conversionOk;
603  int eNr = epsgNrString.toInt( &conversionOk );
604  if ( !conversionOk )
605  {
606  return 1;
607  }
608  epsgNr = eNr;
609  return 0;
610  }
611  ++i;
612  }
613  return 2;
614 }
615 
616 QString QgsGml::readAttribute( const QString& attributeName, const XML_Char** attr ) const
617 {
618  int i = 0;
619  while ( attr[i] )
620  {
621  if ( attributeName.compare( attr[i] ) == 0 )
622  {
623  return QString::fromUtf8( attr[i+1] );
624  }
625  i += 2;
626  }
627  return QString();
628 }
629 
630 int QgsGml::createBBoxFromCoordinateString( QgsRectangle &r, const QString& coordString ) const
631 {
632  QList<QgsPoint> points;
633  if ( pointsFromCoordinateString( points, coordString ) != 0 )
634  {
635  return 2;
636  }
637 
638  if ( points.size() < 2 )
639  {
640  return 3;
641  }
642 
643  r.set( points[0], points[1] );
644 
645  return 0;
646 }
647 
648 int QgsGml::pointsFromCoordinateString( QList<QgsPoint>& points, const QString& coordString ) const
649 {
650  //tuples are separated by space, x/y by ','
651  QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
652  QStringList tuples_coordinates;
653  double x, y;
654  bool conversionSuccess;
655 
656  QStringList::const_iterator tupleIterator;
657  for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
658  {
659  tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
660  if ( tuples_coordinates.size() < 2 )
661  {
662  continue;
663  }
664  x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
665  if ( !conversionSuccess )
666  {
667  continue;
668  }
669  y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
670  if ( !conversionSuccess )
671  {
672  continue;
673  }
674  points.push_back( QgsPoint( x, y ) );
675  }
676  return 0;
677 }
678 
679 int QgsGml::pointsFromPosListString( QList<QgsPoint>& points, const QString& coordString, int dimension ) const
680 {
681  // coordinates separated by spaces
682  QStringList coordinates = coordString.split( ' ', QString::SkipEmptyParts );
683 
684  if ( coordinates.size() % dimension != 0 )
685  {
686  QgsDebugMsg( "Wrong number of coordinates" );
687  }
688 
689  int ncoor = coordinates.size() / dimension;
690  for ( int i = 0; i < ncoor; i++ )
691  {
692  bool conversionSuccess;
693  double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
694  if ( !conversionSuccess )
695  {
696  continue;
697  }
698  double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
699  if ( !conversionSuccess )
700  {
701  continue;
702  }
703  points.append( QgsPoint( x, y ) );
704  }
705  return 0;
706 }
707 
708 int QgsGml::pointsFromString( QList<QgsPoint>& points, const QString& coordString ) const
709 {
710  if ( mCoorMode == QgsGml::coordinate )
711  {
712  return pointsFromCoordinateString( points, coordString );
713  }
714  else if ( mCoorMode == QgsGml::posList )
715  {
716  return pointsFromPosListString( points, coordString, mDimension );
717  }
718  return 1;
719 }
720 
721 int QgsGml::getPointWKB( QgsWkbPtr &wkbPtr, const QgsPoint& point ) const
722 {
723  int wkbSize = 1 + sizeof( int ) + 2 * sizeof( double );
724  wkbPtr = QgsWkbPtr( new unsigned char[wkbSize], wkbSize );
725 
726  QgsWkbPtr fillPtr( wkbPtr );
727  fillPtr << mEndian << QGis::WKBPoint << point.x() << point.y();
728 
729  return 0;
730 }
731 
732 int QgsGml::getLineWKB( QgsWkbPtr &wkbPtr, const QList<QgsPoint>& lineCoordinates ) const
733 {
734  int wkbSize = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double );
735  wkbPtr = QgsWkbPtr( new unsigned char[wkbSize], wkbSize );
736 
737  QgsWkbPtr fillPtr( wkbPtr );
738 
739  fillPtr << mEndian << QGis::WKBLineString << lineCoordinates.size();
740 
742  for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
743  {
744  fillPtr << iter->x() << iter->y();
745  }
746 
747  return 0;
748 }
749 
750 int QgsGml::getRingWKB( QgsWkbPtr &wkbPtr, const QList<QgsPoint>& ringCoordinates ) const
751 {
752  int wkbSize = sizeof( int ) + ringCoordinates.size() * 2 * sizeof( double );
753  wkbPtr = QgsWkbPtr( new unsigned char[wkbSize], wkbSize );
754 
755  QgsWkbPtr fillPtr( wkbPtr );
756 
757  fillPtr << ringCoordinates.size();
758 
760  for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
761  {
762  fillPtr << iter->x() << iter->y();
763  }
764 
765  return 0;
766 }
767 
768 int QgsGml::createMultiLineFromFragments()
769 {
770  int size = 1 + 2 * sizeof( int ) + totalWKBFragmentSize();
771  mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
772 
773  QgsWkbPtr wkbPtr( mCurrentWKB );
774 
775  wkbPtr << mEndian << QGis::WKBMultiLineString << mCurrentWKBFragments.constBegin()->size();
776 
777  //copy (and delete) all the wkb fragments
778  QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
779  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
780  {
781  memcpy( wkbPtr, *wkbIt, wkbIt->size() );
782  wkbPtr += wkbIt->size();
783  delete[] *wkbIt;
784  }
785 
786  mCurrentWKBFragments.clear();
787  *mWkbType = QGis::WKBMultiLineString;
788  return 0;
789 }
790 
791 int QgsGml::createMultiPointFromFragments()
792 {
793  int size = 1 + 2 * sizeof( int ) + totalWKBFragmentSize();
794  mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
795 
796  QgsWkbPtr wkbPtr( mCurrentWKB );
797  wkbPtr << mEndian << QGis::WKBMultiPoint << mCurrentWKBFragments.constBegin()->size();
798 
799  QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
800  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
801  {
802  memcpy( wkbPtr, *wkbIt, wkbIt->size() );
803  wkbPtr += wkbIt->size();
804  delete[] *wkbIt;
805  }
806 
807  mCurrentWKBFragments.clear();
808  *mWkbType = QGis::WKBMultiPoint;
809  return 0;
810 }
811 
812 
813 int QgsGml::createPolygonFromFragments()
814 {
815  int size = 1 + 2 * sizeof( int ) + totalWKBFragmentSize();
816  mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
817 
818  QgsWkbPtr wkbPtr( mCurrentWKB );
819  wkbPtr << mEndian << QGis::WKBPolygon << mCurrentWKBFragments.constBegin()->size();
820 
821  QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
822  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
823  {
824  memcpy( wkbPtr, *wkbIt, wkbIt->size() );
825  wkbPtr += wkbIt->size();
826  delete[] *wkbIt;
827  }
828 
829  mCurrentWKBFragments.clear();
830  *mWkbType = QGis::WKBPolygon;
831  return 0;
832 }
833 
834 int QgsGml::createMultiPolygonFromFragments()
835 {
836  int size = 0;
837  size += 1 + 2 * sizeof( int );
838  size += totalWKBFragmentSize();
839  size += mCurrentWKBFragments.size() * ( 1 + 2 * sizeof( int ) ); //fragments are just the rings
840 
841  mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
842 
843  QgsWkbPtr wkbPtr( mCurrentWKB );
844  wkbPtr << ( char ) mEndian << QGis::WKBMultiPolygon << mCurrentWKBFragments.size();
845 
846  //have outer and inner iterators
847  QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
848 
849  for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
850  {
851  //new polygon
852  wkbPtr << ( char ) mEndian << QGis::WKBPolygon << outerWkbIt->size();
853 
854  QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
855  for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
856  {
857  memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
858  wkbPtr += innerWkbIt->size();
859  delete[] *innerWkbIt;
860  }
861  }
862 
863  mCurrentWKBFragments.clear();
864  *mWkbType = QGis::WKBMultiPolygon;
865  return 0;
866 }
867 
868 int QgsGml::totalWKBFragmentSize() const
869 {
870  int result = 0;
871  Q_FOREACH ( const QList<QgsWkbPtr> &list, mCurrentWKBFragments )
872  {
873  Q_FOREACH ( const QgsWkbPtr &i, list )
874  {
875  result += i.size();
876  }
877  }
878  return result;
879 }
880 
881 void QgsGml::calculateExtentFromFeatures()
882 {
883  if ( mFeatures.size() < 1 )
884  {
885  return;
886  }
887 
888  QgsFeature* currentFeature = nullptr;
889  const QgsGeometry* currentGeometry = nullptr;
890  bool bboxInitialised = false; //gets true once bbox has been set to the first geometry
891 
892  for ( int i = 0; i < mFeatures.size(); ++i )
893  {
894  currentFeature = mFeatures[i];
895  if ( !currentFeature )
896  {
897  continue;
898  }
899  currentGeometry = currentFeature->constGeometry();
900  if ( currentGeometry )
901  {
902  if ( !bboxInitialised )
903  {
904  mExtent = currentGeometry->boundingBox();
905  bboxInitialised = true;
906  }
907  else
908  {
909  mExtent.unionRect( currentGeometry->boundingBox() );
910  }
911  }
912  }
913 }
914 
916 {
918  if ( mEpsg != 0 )
919  {
920  crs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( mEpsg ) );
921  }
922  return crs;
923 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void clear()
void unionRect(const QgsRectangle &rect)
Updates rectangle to include passed argument.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QString & append(QChar ch)
bool isEmpty() const
test if rectangle is empty.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
bool contains(const Key &key) const
static QgsAuthManager * instance()
Enforce singleton pattern.
void push_back(const T &value)
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer&#39;s length...
void setWindowModality(Qt::WindowModality windowModality)
QString errorString() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
void push(const T &t)
const T & at(int i) const
int size() const
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
bool isEmpty() const
Container of fields for a vector layer.
Definition: qgsfield.h:187
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:115
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:222
WkbType
Used for symbology operations.
Definition: qgis.h:57
void dataReadProgress(int progress)
const_iterator constFind(const Key &key) const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
void clear()
double toDouble(bool *ok) const
static endian_t endian()
Returns whether this machine uses big or little endian.
QString tr(const char *sourceText, const char *disambiguation, int n)
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
int size() const
bool isNull() const
void totalStepsUpdate(int totalSteps)
T value(int i) const
void set(const QgsPoint &p1, const QgsPoint &p2)
Set the rectangle from two QgsPoints.
void clear()
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
const char * name() const
void setGeometry(const QgsGeometry &geom)
Set this feature&#39;s geometry from another QgsGeometry object.
Definition: qgsfeature.cpp:124
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
void append(const T &value)
QString fromUtf8(const char *str, int size)
int getFeatures(const QString &uri, QGis::WkbType *wkbType, QgsRectangle *extent=nullptr, const QString &userName=QString(), const QString &password=QString(), const QString &authcfg=QString())
Does the Http GET request to the wfs server Supports only UTF-8, UTF-16, ISO-8859-1, ISO-8859-1 XML encodings.
Definition: qgsgml.cpp:74
void dataProgressAndSteps(int progress, int totalSteps)
This class reads data from a WFS server or alternatively from a GML file.
Definition: qgsgml.h:42
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
Definition: qgsgml.cpp:39
int toInt(bool *ok, int base) const
bool isEmpty() const
bool isEmpty() const
const_iterator constEnd() const
const char * constData() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QByteArray readAll()
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
int size() const
Definition: qgswkbptr.h:81
A class to represent a point.
Definition: qgspoint.h:65
const QString GML_NAMESPACE
Definition: qgsgml.cpp:37
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:204
QString mid(int position, int n) const
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
T & last()
Class for storing a coordinate reference system (CRS)
int size() const
Return number of items.
Definition: qgsfield.cpp:370
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
int length() const
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
NetworkError error() const
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
iterator insert(const Key &key, const T &value)
void show()
const char NS_SEPARATOR
Definition: qgsgml.cpp:36
QNetworkReply * get(const QNetworkRequest &request)
const_iterator constEnd() const
const_iterator constBegin() const
int size() const
A vector of attributes.
Definition: qgsfeature.h:115
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int compare(const QString &other) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
~QgsGml()
Definition: qgsgml.cpp:70
qlonglong toLongLong(bool *ok, int base) const
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
Definition: qgsgml.cpp:915
int size() const
const T value(const Key &key) const
T & top()