QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 
55  mEndian = QgsApplication::endian();
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
79  mExtent.setMinimal();
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
157  calculateExtentFromFeatures();
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;
172  mExtent.setMinimal();
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 
187 void QgsGml::setFinished()
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  {
214  mParseModeStack.push( QgsGml::coordinate );
215  mCoorMode = QgsGml::coordinate;
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  {
231  mParseModeStack.push( QgsGml::posList );
232  mCoorMode = QgsGml::posList;
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  {
244  mParseModeStack.push( QgsGml::geometry );
245  }
246  //else if ( mParseModeStack.size() == 0 && elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
247  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
248  {
249  mParseModeStack.push( QgsGml::boundingBox );
250  }
251  else if ( theParseMode == none && localName == mTypeName )
252  {
253  Q_ASSERT( !mCurrentFeature );
254  mCurrentFeature = new QgsFeature( mFeatureCount );
255  QgsAttributes attributes( mThematicAttributes.size() ); //add empty attributes
256  mCurrentFeature->setAttributes( attributes );
257  mParseModeStack.push( QgsGml::feature );
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  {
277  mParseModeStack.push( QgsGml::multiPoint );
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  {
284  mParseModeStack.push( QgsGml::multiLine );
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  {
291  mParseModeStack.push( QgsGml::multiPolygon );
292  }
293  else if ( theParseMode == feature && mThematicAttributes.contains( localName ) )
294  {
295  mParseModeStack.push( QgsGml::attribute );
296  mAttributeName = localName;
297  mStringCash.clear();
298  }
299  // QGIS server (2.2) is using:
300  // <Attribute value="My description" name="desc"/>
301  else if ( theParseMode == feature
302  && localName.compare( "attribute", Qt::CaseInsensitive ) == 0 )
303  {
304  QString name = readAttribute( "name", attr );
305  if ( mThematicAttributes.contains( name ) )
306  {
307  QString value = readAttribute( "value", attr );
308  setAttribute( name, value );
309  }
310  }
311 
312  if ( mEpsg == 0 && ( localName == "Point" || localName == "MultiPoint" ||
313  localName == "LineString" || localName == "MultiLineString" ||
314  localName == "Polygon" || localName == "MultiPolygon" ) )
315  {
316  if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
317  {
318  QgsDebugMsg( "error, could not get epsg id" );
319  }
320  else
321  {
322  QgsDebugMsg( QString( "mEpsg = %1" ).arg( mEpsg ) );
323  }
324  }
325 }
326 
327 void QgsGml::endElement( const XML_Char* el )
328 {
329  QString elementName( QString::fromUtf8( el ) );
330  ParseMode theParseMode( mParseModeStack.isEmpty() ? none : mParseModeStack.top() );
331  QStringList splitName = elementName.split( NS_SEPARATOR );
332  QString localName = splitName.last();
333  QString ns = splitName.size() > 1 ? splitName.first() : "";
334 
335  if (( theParseMode == coordinate && elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
336  || ( theParseMode == posList && (
337  elementName == GML_NAMESPACE + NS_SEPARATOR + "pos"
338  || elementName == GML_NAMESPACE + NS_SEPARATOR + "posList" ) ) )
339  {
340  mParseModeStack.pop();
341  }
342  else if ( theParseMode == attribute && localName == mAttributeName ) //add a thematic attribute to the feature
343  {
344  mParseModeStack.pop();
345 
346  setAttribute( mAttributeName, mStringCash );
347  }
348  else if ( theParseMode == geometry && localName == mGeometryAttribute )
349  {
350  mParseModeStack.pop();
351  }
352  else if ( theParseMode == boundingBox && elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
353  {
354  //create bounding box from mStringCash
355  if ( createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) != 0 )
356  {
357  QgsDebugMsg( "creation of bounding box failed" );
358  }
359 
360  mParseModeStack.pop();
361  }
362  else if ( theParseMode == feature && localName == mTypeName )
363  {
364  Q_ASSERT( mCurrentFeature );
365  if ( mCurrentWKBSize > 0 )
366  {
367  mCurrentFeature->setGeometryAndOwnership( mCurrentWKB, mCurrentWKBSize );
368  }
369  else if ( !mCurrentExtent.isEmpty() )
370  {
371  mCurrentFeature->setGeometry( QgsGeometry::fromRect( mCurrentExtent ) );
372  }
373  else
374  {
375  mCurrentFeature->setGeometry( 0 );
376  }
377  mCurrentFeature->setValid( true );
378 
379  mFeatures.insert( mCurrentFeature->id(), mCurrentFeature );
380  if ( !mCurrentFeatureId.isEmpty() )
381  {
382  mIdMap.insert( mCurrentFeature->id(), mCurrentFeatureId );
383  }
384  mCurrentFeature = 0;
385  ++mFeatureCount;
386  mParseModeStack.pop();
387  }
388  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Point" )
389  {
390  QList<QgsPoint> pointList;
391  if ( pointsFromString( pointList, mStringCash ) != 0 )
392  {
393  //error
394  }
395 
396  if ( pointList.count() == 0 )
397  return; // error
398 
399  if ( theParseMode == QgsGml::geometry )
400  {
401  //directly add WKB point to the feature
402  if ( getPointWKB( &mCurrentWKB, &mCurrentWKBSize, *( pointList.begin() ) ) != 0 )
403  {
404  //error
405  }
406 
407  if ( *mWkbType != QGis::WKBMultiPoint ) //keep multitype in case of geometry type mix
408  {
409  *mWkbType = QGis::WKBPoint;
410  }
411  }
412  else //multipoint, add WKB as fragment
413  {
414  unsigned char* wkb = 0;
415  int wkbSize = 0;
416  QList<unsigned char*> wkbList;
417  QList<int> wkbSizeList;
418  if ( getPointWKB( &wkb, &wkbSize, *( pointList.begin() ) ) != 0 )
419  {
420  //error
421  }
422  if ( !mCurrentWKBFragments.isEmpty() )
423  {
424  mCurrentWKBFragments.last().push_back( wkb );
425  mCurrentWKBFragmentSizes.last().push_back( wkbSize );
426  }
427  else
428  {
429  QgsDebugMsg( "No wkb fragments" );
430  }
431  }
432  }
433  else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "LineString" )
434  {
435  //add WKB point to the feature
436 
437  QList<QgsPoint> pointList;
438  if ( pointsFromString( pointList, mStringCash ) != 0 )
439  {
440  //error
441  }
442  if ( theParseMode == QgsGml::geometry )
443  {
444  if ( getLineWKB( &mCurrentWKB, &mCurrentWKBSize, pointList ) != 0 )
445  {
446  //error
447  }
448 
449  if ( *mWkbType != QGis::WKBMultiLineString )//keep multitype in case of geometry type mix
450  {
451  *mWkbType = QGis::WKBLineString;
452  }
453  }
454  else //multiline, add WKB as fragment
455  {
456  unsigned char* wkb = 0;
457  int wkbSize = 0;
458  QList<unsigned char*> wkbList;
459  QList<int> wkbSizeList;
460  if ( getLineWKB( &wkb, &wkbSize, pointList ) != 0 )
461  {
462  //error
463  }
464  if ( !mCurrentWKBFragments.isEmpty() )
465  {
466  mCurrentWKBFragments.last().push_back( wkb );
467  mCurrentWKBFragmentSizes.last().push_back( wkbSize );
468  }
469  else
470  {
471  QgsDebugMsg( "no wkb fragments" );
472  }
473  }
474  }
475  else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE + NS_SEPARATOR + "LinearRing" )
476  {
477  QList<QgsPoint> pointList;
478  if ( pointsFromString( pointList, mStringCash ) != 0 )
479  {
480  //error
481  }
482  unsigned char* wkb = 0;
483  int wkbSize = 0;
484  if ( getRingWKB( &wkb, &wkbSize, pointList ) != 0 )
485  {
486  //error
487  }
488  if ( !mCurrentWKBFragments.isEmpty() )
489  {
490  mCurrentWKBFragments.last().push_back( wkb );
491  mCurrentWKBFragmentSizes.last().push_back( wkbSize );
492  }
493  else
494  {
495  QgsDebugMsg( "no wkb fragments" );
496  }
497  }
498  else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
499  {
500  if ( *mWkbType != QGis::WKBMultiPolygon )//keep multitype in case of geometry type mix
501  {
502  *mWkbType = QGis::WKBPolygon;
503  }
504 
505  if ( theParseMode == geometry )
506  {
507  createPolygonFromFragments();
508  }
509  }
510  else if ( theParseMode == multiPoint && elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPoint" )
511  {
512  *mWkbType = QGis::WKBMultiPoint;
513  mParseModeStack.pop();
514  createMultiPointFromFragments();
515  }
516  else if ( theParseMode == multiLine && elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiLineString" )
517  {
518  *mWkbType = QGis::WKBMultiLineString;
519  mParseModeStack.pop();
520  createMultiLineFromFragments();
521  }
522  else if ( theParseMode == multiPolygon && elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPolygon" )
523  {
524  *mWkbType = QGis::WKBMultiPolygon;
525  mParseModeStack.pop();
526  createMultiPolygonFromFragments();
527  }
528 }
529 
530 void QgsGml::characters( const XML_Char* chars, int len )
531 {
532  //save chars in mStringCash attribute mode or coordinate mode
533  if ( mParseModeStack.size() == 0 )
534  {
535  return;
536  }
537 
538  QgsGml::ParseMode theParseMode = mParseModeStack.top();
539  if ( theParseMode == QgsGml::attribute || theParseMode == QgsGml::coordinate || theParseMode == QgsGml::posList )
540  {
541  mStringCash.append( QString::fromUtf8( chars, len ) );
542  }
543 }
544 
545 void QgsGml::setAttribute( const QString& name, const QString& value )
546 {
547  //find index with attribute name
548  QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.find( name );
549  if ( att_it != mThematicAttributes.constEnd() )
550  {
551  QVariant var;
552  switch ( att_it.value().second.type() )
553  {
554  case QVariant::Double:
555  var = QVariant( value.toDouble() );
556  break;
557  case QVariant::Int:
558  var = QVariant( value.toInt() );
559  break;
560  case QVariant::LongLong:
561  var = QVariant( value.toLongLong() );
562  break;
563  default: //string type is default
564  var = QVariant( value );
565  break;
566  }
567  Q_ASSERT( mCurrentFeature );
568  mCurrentFeature->setAttribute( att_it.value().first, var );
569  }
570 }
571 
572 int QgsGml::readEpsgFromAttribute( int& epsgNr, const XML_Char** attr ) const
573 {
574  int i = 0;
575  while ( attr[i] != NULL )
576  {
577  if ( strcmp( attr[i], "srsName" ) == 0 )
578  {
579  QString epsgString( attr[i+1] );
580  QString epsgNrString;
581  if ( epsgString.startsWith( "http" ) ) //e.g. geoserver: "http://www.opengis.net/gml/srs/epsg.xml#4326"
582  {
583  epsgNrString = epsgString.section( "#", 1, 1 );
584  }
585  else //e.g. umn mapserver: "EPSG:4326">
586  {
587  epsgNrString = epsgString.section( ":", 1, 1 );
588  }
589  bool conversionOk;
590  int eNr = epsgNrString.toInt( &conversionOk );
591  if ( !conversionOk )
592  {
593  return 1;
594  }
595  epsgNr = eNr;
596  return 0;
597  }
598  ++i;
599  }
600  return 2;
601 }
602 
603 QString QgsGml::readAttribute( const QString& attributeName, const XML_Char** attr ) const
604 {
605  int i = 0;
606  while ( attr[i] != NULL )
607  {
608  if ( attributeName.compare( attr[i] ) == 0 )
609  {
610  return QString( attr[i+1] );
611  }
612  i += 2;
613  }
614  return QString();
615 }
616 
617 int QgsGml::createBBoxFromCoordinateString( QgsRectangle &r, const QString& coordString ) const
618 {
619  QList<QgsPoint> points;
620  if ( pointsFromCoordinateString( points, coordString ) != 0 )
621  {
622  return 2;
623  }
624 
625  if ( points.size() < 2 )
626  {
627  return 3;
628  }
629 
630  r.set( points[0], points[1] );
631 
632  return 0;
633 }
634 
635 int QgsGml::pointsFromCoordinateString( QList<QgsPoint>& points, const QString& coordString ) const
636 {
637  //tuples are separated by space, x/y by ','
638  QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
639  QStringList tuples_coordinates;
640  double x, y;
641  bool conversionSuccess;
642 
643  QStringList::const_iterator tupleIterator;
644  for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
645  {
646  tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
647  if ( tuples_coordinates.size() < 2 )
648  {
649  continue;
650  }
651  x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
652  if ( !conversionSuccess )
653  {
654  continue;
655  }
656  y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
657  if ( !conversionSuccess )
658  {
659  continue;
660  }
661  points.push_back( QgsPoint( x, y ) );
662  }
663  return 0;
664 }
665 
666 int QgsGml::pointsFromPosListString( QList<QgsPoint>& points, const QString& coordString, int dimension ) const
667 {
668  // coordinates separated by spaces
669  QStringList coordinates = coordString.split( " ", QString::SkipEmptyParts );
670 
671  if ( coordinates.size() % dimension != 0 )
672  {
673  QgsDebugMsg( "Wrong number of coordinates" );
674  }
675 
676  int ncoor = coordinates.size() / dimension;
677  for ( int i = 0; i < ncoor; i++ )
678  {
679  bool conversionSuccess;
680  double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
681  if ( !conversionSuccess )
682  {
683  continue;
684  }
685  double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
686  if ( !conversionSuccess )
687  {
688  continue;
689  }
690  points.append( QgsPoint( x, y ) );
691  }
692  return 0;
693 }
694 
695 int QgsGml::pointsFromString( QList<QgsPoint>& points, const QString& coordString ) const
696 {
697  if ( mCoorMode == QgsGml::coordinate )
698  {
699  return pointsFromCoordinateString( points, coordString );
700  }
701  else if ( mCoorMode == QgsGml::posList )
702  {
703  return pointsFromPosListString( points, coordString, mDimension );
704  }
705  return 1;
706 }
707 
708 int QgsGml::getPointWKB( unsigned char** wkb, int* size, const QgsPoint& point ) const
709 {
710  int wkbSize = 1 + sizeof( int ) + 2 * sizeof( double );
711  *size = wkbSize;
712  *wkb = new unsigned char[wkbSize];
714  double x = point.x();
715  double y = point.y();
716  int wkbPosition = 0; //current offset from wkb beginning (in bytes)
717 
718  memcpy( &( *wkb )[wkbPosition], &mEndian, 1 );
719  wkbPosition += 1;
720  memcpy( &( *wkb )[wkbPosition], &type, sizeof( int ) );
721  wkbPosition += sizeof( int );
722  memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) );
723  wkbPosition += sizeof( double );
724  memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) );
725  return 0;
726 }
727 
728 int QgsGml::getLineWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& lineCoordinates ) const
729 {
730  int wkbSize = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double );
731  *size = wkbSize;
732  *wkb = new unsigned char[wkbSize];
734  int wkbPosition = 0; //current offset from wkb beginning (in bytes)
735  double x, y;
736  int nPoints = lineCoordinates.size();
737 
738  //fill the contents into *wkb
739  memcpy( &( *wkb )[wkbPosition], &mEndian, 1 );
740  wkbPosition += 1;
741  memcpy( &( *wkb )[wkbPosition], &type, sizeof( int ) );
742  wkbPosition += sizeof( int );
743  memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) );
744  wkbPosition += sizeof( int );
745 
746  QList<QgsPoint>::const_iterator iter;
747  for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter )
748  {
749  x = iter->x();
750  y = iter->y();
751  memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) );
752  wkbPosition += sizeof( double );
753  memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) );
754  wkbPosition += sizeof( double );
755  }
756  return 0;
757 }
758 
759 int QgsGml::getRingWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& ringCoordinates ) const
760 {
761  int wkbSize = sizeof( int ) + ringCoordinates.size() * 2 * sizeof( double );
762  *size = wkbSize;
763  *wkb = new unsigned char[wkbSize];
764  int wkbPosition = 0; //current offset from wkb beginning (in bytes)
765  double x, y;
766  int nPoints = ringCoordinates.size();
767  memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) );
768  wkbPosition += sizeof( int );
769 
770  QList<QgsPoint>::const_iterator iter;
771  for ( iter = ringCoordinates.begin(); iter != ringCoordinates.end(); ++iter )
772  {
773  x = iter->x();
774  y = iter->y();
775  memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) );
776  wkbPosition += sizeof( double );
777  memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) );
778  wkbPosition += sizeof( double );
779  }
780  return 0;
781 }
782 
783 int QgsGml::createMultiLineFromFragments()
784 {
785  mCurrentWKBSize = 0;
786  mCurrentWKBSize += 1 + 2 * sizeof( int );
787  mCurrentWKBSize += totalWKBFragmentSize();
788 
789  mCurrentWKB = new unsigned char[mCurrentWKBSize];
790  int pos = 0;
792  int numLines = mCurrentWKBFragments.begin()->size();
793  //add endian
794  memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
795  pos += 1;
796  memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
797  pos += sizeof( int );
798  memcpy( &( mCurrentWKB[pos] ), &numLines, sizeof( int ) );
799  pos += sizeof( int );
800  QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
801  QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
802 
803  //copy (and delete) all the wkb fragments
804  for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
805  {
806  memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
807  pos += *sizeIt;
808  delete[] *wkbIt;
809  }
810 
811  mCurrentWKBFragments.clear();
812  mCurrentWKBFragmentSizes.clear();
813  *mWkbType = QGis::WKBMultiLineString;
814  return 0;
815 }
816 
817 int QgsGml::createMultiPointFromFragments()
818 {
819  mCurrentWKBSize = 0;
820  mCurrentWKBSize += 1 + 2 * sizeof( int );
821  mCurrentWKBSize += totalWKBFragmentSize();
822  mCurrentWKB = new unsigned char[mCurrentWKBSize];
823 
824  int pos = 0;
826  int numPoints = mCurrentWKBFragments.begin()->size();
827 
828  memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
829  pos += 1;
830  memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
831  pos += sizeof( int );
832  memcpy( &( mCurrentWKB[pos] ), &numPoints, sizeof( int ) );
833  pos += sizeof( int );
834 
835  QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
836  QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
837 
838  for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
839  {
840  memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
841  pos += *sizeIt;
842  delete[] *wkbIt;
843  }
844 
845  mCurrentWKBFragments.clear();
846  mCurrentWKBFragmentSizes.clear();
847  *mWkbType = QGis::WKBMultiPoint;
848  return 0;
849 }
850 
851 
852 int QgsGml::createPolygonFromFragments()
853 {
854  mCurrentWKBSize = 0;
855  mCurrentWKBSize += 1 + 2 * sizeof( int );
856  mCurrentWKBSize += totalWKBFragmentSize();
857 
858  mCurrentWKB = new unsigned char[mCurrentWKBSize];
859  int pos = 0;
861  int numRings = mCurrentWKBFragments.begin()->size();
862  memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
863  pos += 1;
864  memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
865  pos += sizeof( int );
866  memcpy( &( mCurrentWKB[pos] ), &numRings, sizeof( int ) );
867  pos += sizeof( int );
868 
869  QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
870  QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
871  for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
872  {
873  memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
874  pos += *sizeIt;
875  delete[] *wkbIt;
876  }
877 
878  mCurrentWKBFragments.clear();
879  mCurrentWKBFragmentSizes.clear();
880  *mWkbType = QGis::WKBPolygon;
881  return 0;
882 }
883 
884 int QgsGml::createMultiPolygonFromFragments()
885 {
886  mCurrentWKBSize = 0;
887  mCurrentWKBSize += 1 + 2 * sizeof( int );
888  mCurrentWKBSize += totalWKBFragmentSize();
889  mCurrentWKBSize += mCurrentWKBFragments.size() * ( 1 + 2 * sizeof( int ) ); //fragments are just the rings
890 
891  mCurrentWKB = new unsigned char[mCurrentWKBSize];
892  int pos = 0;
894  QGis::WkbType polygonType = QGis::WKBPolygon;
895  int numPolys = mCurrentWKBFragments.size();
896  int numRings;
897  memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
898  pos += 1;
899  memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
900  pos += sizeof( int );
901  memcpy( &( mCurrentWKB[pos] ), &numPolys, sizeof( int ) );
902  pos += sizeof( int );
903 
904  //have outer and inner iterators
905  QList< QList<unsigned char*> >::iterator outerWkbIt;
906  QList< QList<int> >::iterator outerSizeIt;
907  QList< unsigned char* >::iterator innerWkbIt;
908  QList< int >::iterator innerSizeIt;
909 
910  outerWkbIt = mCurrentWKBFragments.begin();
911  outerSizeIt = mCurrentWKBFragmentSizes.begin();
912 
913  for ( ; outerWkbIt != mCurrentWKBFragments.end(); ++outerWkbIt, ++outerSizeIt )
914  {
915  //new polygon
916  memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
917  pos += 1;
918  memcpy( &( mCurrentWKB[pos] ), &polygonType, sizeof( int ) );
919  pos += sizeof( int );
920  numRings = outerWkbIt->size();
921  memcpy( &( mCurrentWKB[pos] ), &numRings, sizeof( int ) );
922  pos += sizeof( int );
923 
924  innerWkbIt = outerWkbIt->begin();
925  innerSizeIt = outerSizeIt->begin();
926  for ( ; innerWkbIt != outerWkbIt->end(); ++innerWkbIt, ++innerSizeIt )
927  {
928  memcpy( &( mCurrentWKB[pos] ), *innerWkbIt, *innerSizeIt );
929  pos += *innerSizeIt;
930  delete[] *innerWkbIt;
931  }
932  }
933 
934  mCurrentWKBFragments.clear();
935  mCurrentWKBFragmentSizes.clear();
936  *mWkbType = QGis::WKBMultiPolygon;
937  return 0;
938 }
939 
940 int QgsGml::totalWKBFragmentSize() const
941 {
942  int result = 0;
943  foreach ( const QList<int> &list, mCurrentWKBFragmentSizes )
944  {
945  foreach ( int i, list )
946  {
947  result += i;
948  }
949  }
950  return result;
951 }
952 
953 void QgsGml::calculateExtentFromFeatures()
954 {
955  if ( mFeatures.size() < 1 )
956  {
957  return;
958  }
959 
960  QgsFeature* currentFeature = 0;
961  QgsGeometry* currentGeometry = 0;
962  bool bboxInitialised = false; //gets true once bbox has been set to the first geometry
963 
964  for ( int i = 0; i < mFeatures.size(); ++i )
965  {
966  currentFeature = mFeatures[i];
967  if ( !currentFeature )
968  {
969  continue;
970  }
971  currentGeometry = currentFeature->geometry();
972  if ( currentGeometry )
973  {
974  if ( !bboxInitialised )
975  {
976  mExtent = currentGeometry->boundingBox();
977  bboxInitialised = true;
978  }
979  else
980  {
981  mExtent.unionRect( currentGeometry->boundingBox() );
982  }
983  }
984  }
985 }
986 
988 {
990  if ( mEpsg != 0 )
991  {
992  crs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( mEpsg ) );
993  }
994  return crs;
995 }
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
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
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.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:112
Container of fields for a vector layer.
Definition: qgsfield.h:172
void setAttributes(const QgsAttributes &attrs)
Definition: qgsfeature.h:144
bool setAttribute(int field, const QVariant &attr)
Set an attribute by id.
Definition: qgsfeature.cpp:190
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:113
static endian_t endian()
Returns whether this machine uses big or little endian.
double x() const
Definition: qgspoint.h:126
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)
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
void dataProgressAndSteps(int progress, int totalSteps)
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
Definition: qgsgml.cpp:36
A class to represent a point.
Definition: qgspoint.h:63
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.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:100
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)
int size() const
Return number of items.
Definition: qgsfield.h:216
static QgsGeometry * fromRect(const QgsRectangle &rect)
construct geometry from a rectangle
double y() const
Definition: qgspoint.h:134
const char NS_SEPARATOR
Definition: qgsgml.cpp:33
double size
Definition: qgssvgcache.cpp:77
~QgsGml()
Definition: qgsgml.cpp:64
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
Definition: qgsgml.cpp:987
void setGeometryAndOwnership(unsigned char *geom, size_t length)
Set this feature's geometry from WKB.
Definition: qgsfeature.cpp:154
#define tr(sourceText)