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