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