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