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