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