QGIS API Documentation  master-59fd5e0
src/core/qgsgml.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsgml.cpp
00003     ---------------------
00004     begin                : February 2013
00005     copyright            : (C) 2013 by Radim Blazek
00006     email                : radim dot blazek at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 #include "qgsgml.h"
00016 #include "qgsrectangle.h"
00017 #include "qgscoordinatereferencesystem.h"
00018 #include "qgsgeometry.h"
00019 #include "qgslogger.h"
00020 #include "qgsmessagelog.h"
00021 #include "qgsnetworkaccessmanager.h"
00022 #include <QBuffer>
00023 #include <QList>
00024 #include <QNetworkRequest>
00025 #include <QNetworkReply>
00026 #include <QProgressDialog>
00027 #include <QSet>
00028 #include <QSettings>
00029 #include <QUrl>
00030 
00031 #include <limits>
00032 
00033 const char NS_SEPARATOR = '?';
00034 const QString GML_NAMESPACE = "http://www.opengis.net/gml";
00035 
00036 QgsGml::QgsGml(
00037   const QString& typeName,
00038   const QString& geometryAttribute,
00039   const QgsFields & fields )
00040     : QObject()
00041     , mTypeName( typeName )
00042     , mGeometryAttribute( geometryAttribute )
00043     , mFinished( false )
00044     , mFeatureCount( 0 )
00045     , mCurrentWKBSize( 0 )
00046 {
00047   mThematicAttributes.clear();
00048   for ( int i = 0; i < fields.size(); i++ )
00049   {
00050     mThematicAttributes.insert( fields[i].name(), qMakePair( i, fields[i] ) );
00051   }
00052 
00053   mEndian = QgsApplication::endian();
00054 
00055   int index = mTypeName.indexOf( ":" );
00056   if ( index != -1 && index < mTypeName.length() )
00057   {
00058     mTypeName = mTypeName.mid( index + 1 );
00059   }
00060 }
00061 
00062 QgsGml::~QgsGml()
00063 {
00064 }
00065 
00066 int QgsGml::getFeatures( const QString& uri, QGis::WkbType* wkbType, QgsRectangle* extent )
00067 {
00068   mUri = uri;
00069   mWkbType = wkbType;
00070 
00071   XML_Parser p = XML_ParserCreateNS( NULL, NS_SEPARATOR );
00072   XML_SetUserData( p, this );
00073   XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
00074   XML_SetCharacterDataHandler( p, QgsGml::chars );
00075 
00076   //start with empty extent
00077   mExtent.setMinimal();
00078 
00079   QNetworkRequest request( mUri );
00080   QNetworkReply* reply = QgsNetworkAccessManager::instance()->get( request );
00081 
00082   connect( reply, SIGNAL( finished() ), this, SLOT( setFinished() ) );
00083   connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( handleProgressEvent( qint64, qint64 ) ) );
00084 
00085   //find out if there is a QGIS main window. If yes, display a progress dialog
00086   QProgressDialog* progressDialog = 0;
00087   QWidget* mainWindow = qApp->activeWindow();
00088   if ( mainWindow )
00089   {
00090     progressDialog = new QProgressDialog( tr( "Loading GML data\n%1" ).arg( mTypeName ), tr( "Abort" ), 0, 0, mainWindow );
00091     progressDialog->setWindowModality( Qt::ApplicationModal );
00092     connect( this, SIGNAL( dataReadProgress( int ) ), progressDialog, SLOT( setValue( int ) ) );
00093     connect( this, SIGNAL( totalStepsUpdate( int ) ), progressDialog, SLOT( setMaximum( int ) ) );
00094     connect( progressDialog, SIGNAL( canceled() ), this, SLOT( setFinished() ) );
00095     progressDialog->show();
00096   }
00097 
00098   int atEnd = 0;
00099   while ( !atEnd )
00100   {
00101     if ( mFinished )
00102     {
00103       atEnd = 1;
00104     }
00105     QByteArray readData = reply->readAll();
00106     if ( readData.size() > 0 )
00107     {
00108       if ( XML_Parse( p, readData.constData(), readData.size(), atEnd ) == 0 )
00109       {
00110         XML_Error errorCode = XML_GetErrorCode( p );
00111         QString errorString = tr( "Error: %1 on line %2, column %3" )
00112                               .arg( XML_ErrorString( errorCode ) )
00113                               .arg( XML_GetCurrentLineNumber( p ) )
00114                               .arg( XML_GetCurrentColumnNumber( p ) );
00115         QgsMessageLog::instance()->logMessage( errorString, tr( "WFS" ) );
00116       }
00117     }
00118     QCoreApplication::processEvents();
00119   }
00120 
00121   delete reply;
00122   delete progressDialog;
00123 
00124   if ( *mWkbType != QGis::WKBNoGeometry )
00125   {
00126     if ( mExtent.isEmpty() )
00127     {
00128       //reading of bbox from the server failed, so we calculate it less efficiently by evaluating the features
00129       calculateExtentFromFeatures();
00130     }
00131   }
00132 
00133   XML_ParserFree( p );
00134 
00135   if ( extent )
00136     *extent = mExtent;
00137 
00138   return 0;
00139 }
00140 
00141 int QgsGml::getFeatures( const QByteArray &data, QGis::WkbType* wkbType, QgsRectangle* extent )
00142 {
00143   QgsDebugMsg( "Entered" );
00144   mWkbType = wkbType;
00145   mExtent.setMinimal();
00146 
00147   XML_Parser p = XML_ParserCreateNS( NULL, NS_SEPARATOR );
00148   XML_SetUserData( p, this );
00149   XML_SetElementHandler( p, QgsGml::start, QgsGml::end );
00150   XML_SetCharacterDataHandler( p, QgsGml::chars );
00151   int atEnd = 1;
00152   XML_Parse( p, data.constData(), data.size(), atEnd );
00153 
00154   if ( extent )
00155     *extent = mExtent;
00156 
00157   return 0;
00158 }
00159 
00160 void QgsGml::setFinished( )
00161 {
00162   mFinished = true;
00163 }
00164 
00165 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
00166 {
00167   emit dataReadProgress( progress );
00168   if ( totalSteps < 0 )
00169   {
00170     totalSteps = 0;
00171   }
00172   emit totalStepsUpdate( totalSteps );
00173   emit dataProgressAndSteps( progress, totalSteps );
00174 }
00175 
00176 void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
00177 {
00178   QString elementName( el );
00179   QStringList splitName =  elementName.split( NS_SEPARATOR );
00180   QString localName = splitName.last();
00181   QString ns = splitName.size() > 1 ? splitName.first() : "";
00182   if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
00183   {
00184     mParseModeStack.push( QgsGml::coordinate );
00185     mStringCash.clear();
00186     mCoordinateSeparator = readAttribute( "cs", attr );
00187     if ( mCoordinateSeparator.isEmpty() )
00188     {
00189       mCoordinateSeparator = ",";
00190     }
00191     mTupleSeparator = readAttribute( "ts", attr );
00192     if ( mTupleSeparator.isEmpty() )
00193     {
00194       mTupleSeparator = " ";
00195     }
00196   }
00197   else if ( localName == mGeometryAttribute )
00198   {
00199     mParseModeStack.push( QgsGml::geometry );
00200   }
00201   //else if ( mParseModeStack.size() == 0 && elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
00202   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
00203   {
00204     mParseModeStack.push( QgsGml::boundingBox );
00205   }
00206   else if ( localName == mTypeName )
00207   {
00208     mCurrentFeature = new QgsFeature( mFeatureCount );
00209     QgsAttributes attributes( mThematicAttributes.size() ); //add empty attributes
00210     mCurrentFeature->setAttributes( attributes );
00211     mParseModeStack.push( QgsGml::feature );
00212     mCurrentFeatureId = readAttribute( "fid", attr );
00213   }
00214 
00215   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Box" && mParseModeStack.top() == QgsGml::boundingBox )
00216   {
00217     //read attribute srsName="EPSG:26910"
00218     int epsgNr;
00219     if ( readEpsgFromAttribute( epsgNr, attr ) != 0 )
00220     {
00221       QgsDebugMsg( "error, could not get epsg id" );
00222     }
00223   }
00224   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
00225   {
00226     QList<unsigned char*> wkbList;
00227     QList<int> wkbSizeList;
00228     mCurrentWKBFragments.push_back( wkbList );
00229     mCurrentWKBFragmentSizes.push_back( wkbSizeList );
00230   }
00231   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPoint" )
00232   {
00233     mParseModeStack.push( QgsGml::multiPoint );
00234     //we need one nested list for intermediate WKB
00235     QList<unsigned char*> wkbList;
00236     QList<int> wkbSizeList;
00237     mCurrentWKBFragments.push_back( wkbList );
00238     mCurrentWKBFragmentSizes.push_back( wkbSizeList );
00239   }
00240   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiLineString" )
00241   {
00242     mParseModeStack.push( QgsGml::multiLine );
00243     //we need one nested list for intermediate WKB
00244     QList<unsigned char*> wkbList;
00245     QList<int> wkbSizeList;
00246     mCurrentWKBFragments.push_back( wkbList );
00247     mCurrentWKBFragmentSizes.push_back( wkbSizeList );
00248   }
00249   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPolygon" )
00250   {
00251     mParseModeStack.push( QgsGml::multiPolygon );
00252   }
00253   else if (( mParseModeStack.size() > 0 ) && ( mParseModeStack.top() == QgsGml::feature ) && ( mThematicAttributes.find( localName ) != mThematicAttributes.end() ) )
00254   {
00255     mParseModeStack.push( QgsGml::attribute );
00256     mAttributeName = localName;
00257     mStringCash.clear();
00258   }
00259 }
00260 
00261 void QgsGml::endElement( const XML_Char* el )
00262 {
00263   QString elementName( el );
00264   QStringList splitName =  elementName.split( NS_SEPARATOR );
00265   QString localName = splitName.last();
00266   QString ns = splitName.size() > 1 ? splitName.first() : "";
00267   if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
00268   {
00269     if ( !mParseModeStack.empty() )
00270     {
00271       mParseModeStack.pop();
00272     }
00273   }
00274   else if ( localName == mAttributeName ) //add a thematic attribute to the feature
00275   {
00276     if ( !mParseModeStack.empty() )
00277     {
00278       mParseModeStack.pop();
00279     }
00280 
00281     //find index with attribute name
00282     QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.find( mAttributeName );
00283     if ( att_it != mThematicAttributes.constEnd() )
00284     {
00285       QVariant var;
00286       switch ( att_it.value().second.type() )
00287       {
00288         case QVariant::Double:
00289           var = QVariant( mStringCash.toDouble() );
00290           break;
00291         case QVariant::Int:
00292           var = QVariant( mStringCash.toInt() );
00293           break;
00294         case QVariant::LongLong:
00295           var = QVariant( mStringCash.toLongLong() );
00296           break;
00297         default: //string type is default
00298           var = QVariant( mStringCash );
00299           break;
00300       }
00301       mCurrentFeature->setAttribute( att_it.value().first, QVariant( mStringCash ) );
00302     }
00303   }
00304   else if ( localName == mGeometryAttribute )
00305   {
00306     if ( !mParseModeStack.empty() )
00307     {
00308       mParseModeStack.pop();
00309     }
00310   }
00311   else if ( !mParseModeStack.empty() && mParseModeStack.top() == QgsGml::boundingBox && elementName == GML_NAMESPACE + NS_SEPARATOR + "boundedBy" )
00312   {
00313     //create bounding box from mStringCash
00314     if ( createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) != 0 )
00315     {
00316       QgsDebugMsg( "creation of bounding box failed" );
00317     }
00318 
00319     if ( !mParseModeStack.empty() )
00320     {
00321       mParseModeStack.pop();
00322     }
00323   }
00324   else if ( localName == mTypeName )
00325   {
00326     if ( mCurrentWKBSize > 0 )
00327     {
00328       mCurrentFeature->setGeometryAndOwnership( mCurrentWKB, mCurrentWKBSize );
00329     }
00330     else if ( !mCurrentExtent.isEmpty() )
00331     {
00332       mCurrentFeature->setGeometry( QgsGeometry::fromRect( mCurrentExtent ) );
00333     }
00334     else
00335     {
00336       mCurrentFeature->setGeometry( 0 );
00337     }
00338     mCurrentFeature->setValid( true );
00339 
00340     mFeatures.insert( mCurrentFeature->id(), mCurrentFeature );
00341     if ( !mCurrentFeatureId.isEmpty() )
00342     {
00343       mIdMap.insert( mCurrentFeature->id(), mCurrentFeatureId );
00344     }
00345     ++mFeatureCount;
00346     if ( !mParseModeStack.empty() )
00347     {
00348       mParseModeStack.pop();
00349     }
00350   }
00351   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Point" )
00352   {
00353     QList<QgsPoint> pointList;
00354     if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
00355     {
00356       //error
00357     }
00358 
00359     if ( mParseModeStack.top() != QgsGml::multiPoint )
00360     {
00361       //directly add WKB point to the feature
00362       if ( getPointWKB( &mCurrentWKB, &mCurrentWKBSize, *( pointList.begin() ) ) != 0 )
00363       {
00364         //error
00365       }
00366 
00367       if ( *mWkbType != QGis::WKBMultiPoint ) //keep multitype in case of geometry type mix
00368       {
00369         *mWkbType = QGis::WKBPoint;
00370       }
00371     }
00372     else //multipoint, add WKB as fragment
00373     {
00374       unsigned char* wkb = 0;
00375       int wkbSize = 0;
00376       QList<unsigned char*> wkbList;
00377       QList<int> wkbSizeList;
00378       if ( getPointWKB( &wkb, &wkbSize, *( pointList.begin() ) ) != 0 )
00379       {
00380         //error
00381       }
00382       if ( !mCurrentWKBFragments.isEmpty() )
00383       {
00384         mCurrentWKBFragments.begin()->push_back( wkb );
00385         mCurrentWKBFragmentSizes.begin()->push_back( wkbSize );
00386       }
00387       else
00388       {
00389         QgsDebugMsg( "No wkb fragments" );
00390       }
00391 
00392       //wkbList.push_back(wkb);
00393       //wkbSizeList.push_back(wkbSize);
00394       //mCurrentWKBFragments.push_back(wkbList);
00395       //mCurrentWKBFragmentSizes.push_back(wkbSizeList);
00396     }
00397   }
00398   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "LineString" )
00399   {
00400     //add WKB point to the feature
00401 
00402     QList<QgsPoint> pointList;
00403     if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
00404     {
00405       //error
00406     }
00407     if ( mParseModeStack.top() != QgsGml::multiLine )
00408     {
00409       if ( getLineWKB( &mCurrentWKB, &mCurrentWKBSize, pointList ) != 0 )
00410       {
00411         //error
00412       }
00413 
00414       if ( *mWkbType != QGis::WKBMultiLineString )//keep multitype in case of geometry type mix
00415       {
00416         *mWkbType = QGis::WKBLineString;
00417       }
00418     }
00419     else //multiline, add WKB as fragment
00420     {
00421       unsigned char* wkb = 0;
00422       int wkbSize = 0;
00423       QList<unsigned char*> wkbList;
00424       QList<int> wkbSizeList;
00425       if ( getLineWKB( &wkb, &wkbSize, pointList ) != 0 )
00426       {
00427         //error
00428       }
00429       if ( !mCurrentWKBFragments.isEmpty() )
00430       {
00431         mCurrentWKBFragments.begin()->push_back( wkb );
00432         mCurrentWKBFragmentSizes.begin()->push_back( wkbSize );
00433       }
00434       else
00435       {
00436         QgsDebugMsg( "no wkb fragments" );
00437       }
00438       //wkbList.push_back(wkb);
00439       //wkbSizeList.push_back(wkbSize);
00440       //mCurrentWKBFragments.push_back(wkbList);
00441       //mCurrentWKBFragmentSizes.push_back(wkbSizeList);
00442     }
00443   }
00444   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "LinearRing" )
00445   {
00446     QList<QgsPoint> pointList;
00447     if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
00448     {
00449       //error
00450     }
00451     unsigned char* wkb = 0;
00452     int wkbSize = 0;
00453     if ( getRingWKB( &wkb, &wkbSize, pointList ) != 0 )
00454     {
00455       //error
00456     }
00457     if ( !mCurrentWKBFragments.isEmpty() )
00458     {
00459       mCurrentWKBFragments.begin()->push_back( wkb );
00460       mCurrentWKBFragmentSizes.begin()->push_back( wkbSize );
00461     }
00462     else
00463     {
00464       QgsDebugMsg( "no wkb fragments" );
00465     }
00466   }
00467   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Polygon" )
00468   {
00469     if ( *mWkbType != QGis::WKBMultiPolygon )//keep multitype in case of geometry type mix
00470     {
00471       *mWkbType = QGis::WKBPolygon;
00472     }
00473     if ( mParseModeStack.top() != QgsGml::multiPolygon )
00474     {
00475       createPolygonFromFragments();
00476     }
00477   }
00478   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPoint" )
00479   {
00480     *mWkbType = QGis::WKBMultiPoint;
00481     if ( !mParseModeStack.empty() )
00482     {
00483       mParseModeStack.pop();
00484     }
00485     createMultiPointFromFragments();
00486   }
00487   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiLineString" )
00488   {
00489     *mWkbType = QGis::WKBMultiLineString;
00490     if ( !mParseModeStack.empty() )
00491     {
00492       mParseModeStack.pop();
00493     }
00494     createMultiLineFromFragments();
00495   }
00496   else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "MultiPolygon" )
00497   {
00498     *mWkbType = QGis::WKBMultiPolygon;
00499     if ( !mParseModeStack.empty() )
00500     {
00501       mParseModeStack.pop();
00502     }
00503     createMultiPolygonFromFragments();
00504   }
00505 }
00506 
00507 void QgsGml::characters( const XML_Char* chars, int len )
00508 {
00509   //save chars in mStringCash attribute mode or coordinate mode
00510   if ( mParseModeStack.size() == 0 )
00511   {
00512     return;
00513   }
00514 
00515   QgsGml::ParseMode theParseMode = mParseModeStack.top();
00516   if ( theParseMode == QgsGml::attribute || theParseMode == QgsGml::coordinate )
00517   {
00518     mStringCash.append( QString::fromUtf8( chars, len ) );
00519   }
00520 }
00521 
00522 int QgsGml::readEpsgFromAttribute( int& epsgNr, const XML_Char** attr ) const
00523 {
00524   int i = 0;
00525   while ( attr[i] != NULL )
00526   {
00527     if ( strcmp( attr[i], "srsName" ) == 0 )
00528     {
00529       QString epsgString( attr[i+1] );
00530       QString epsgNrString;
00531       if ( epsgString.startsWith( "http" ) ) //e.g. geoserver: "http://www.opengis.net/gml/srs/epsg.xml#4326"
00532       {
00533         epsgNrString = epsgString.section( "#", 1, 1 );
00534       }
00535       else //e.g. umn mapserver: "EPSG:4326">
00536       {
00537         epsgNrString = epsgString.section( ":", 1, 1 );
00538       }
00539       bool conversionOk;
00540       int eNr = epsgNrString.toInt( &conversionOk );
00541       if ( !conversionOk )
00542       {
00543         return 1;
00544       }
00545       epsgNr = eNr;
00546       return 0;
00547     }
00548     ++i;
00549   }
00550   return 2;
00551 }
00552 
00553 QString QgsGml::readAttribute( const QString& attributeName, const XML_Char** attr ) const
00554 {
00555   int i = 0;
00556   while ( attr[i] != NULL )
00557   {
00558     if ( attributeName.compare( attr[i] ) == 0 )
00559     {
00560       return QString( attr[i+1] );
00561     }
00562     ++i;
00563   }
00564   return QString();
00565 }
00566 
00567 int QgsGml::createBBoxFromCoordinateString( QgsRectangle &r, const QString& coordString ) const
00568 {
00569   QList<QgsPoint> points;
00570   if ( pointsFromCoordinateString( points, coordString ) != 0 )
00571   {
00572     return 2;
00573   }
00574 
00575   if ( points.size() < 2 )
00576   {
00577     return 3;
00578   }
00579 
00580   r.set( points[0], points[1] );
00581 
00582   return 0;
00583 }
00584 
00585 int QgsGml::pointsFromCoordinateString( QList<QgsPoint>& points, const QString& coordString ) const
00586 {
00587   //tuples are separated by space, x/y by ','
00588   QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
00589   QStringList tuples_coordinates;
00590   double x, y;
00591   bool conversionSuccess;
00592 
00593   QStringList::const_iterator tupleIterator;
00594   for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
00595   {
00596     tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
00597     if ( tuples_coordinates.size() < 2 )
00598     {
00599       continue;
00600     }
00601     x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
00602     if ( !conversionSuccess )
00603     {
00604       continue;
00605     }
00606     y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
00607     if ( !conversionSuccess )
00608     {
00609       continue;
00610     }
00611     points.push_back( QgsPoint( x, y ) );
00612   }
00613   return 0;
00614 }
00615 
00616 int QgsGml::getPointWKB( unsigned char** wkb, int* size, const QgsPoint& point ) const
00617 {
00618   int wkbSize = 1 + sizeof( int ) + 2 * sizeof( double );
00619   *size = wkbSize;
00620   *wkb = new unsigned char[wkbSize];
00621   QGis::WkbType type = QGis::WKBPoint;
00622   double x = point.x();
00623   double y = point.y();
00624   int wkbPosition = 0; //current offset from wkb beginning (in bytes)
00625 
00626   memcpy( &( *wkb )[wkbPosition], &mEndian, 1 );
00627   wkbPosition += 1;
00628   memcpy( &( *wkb )[wkbPosition], &type, sizeof( int ) );
00629   wkbPosition += sizeof( int );
00630   memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) );
00631   wkbPosition += sizeof( double );
00632   memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) );
00633   return 0;
00634 }
00635 
00636 int QgsGml::getLineWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& lineCoordinates ) const
00637 {
00638   int wkbSize = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double );
00639   *size = wkbSize;
00640   *wkb = new unsigned char[wkbSize];
00641   QGis::WkbType type = QGis::WKBLineString;
00642   int wkbPosition = 0; //current offset from wkb beginning (in bytes)
00643   double x, y;
00644   int nPoints = lineCoordinates.size();
00645 
00646   //fill the contents into *wkb
00647   memcpy( &( *wkb )[wkbPosition], &mEndian, 1 );
00648   wkbPosition += 1;
00649   memcpy( &( *wkb )[wkbPosition], &type, sizeof( int ) );
00650   wkbPosition += sizeof( int );
00651   memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) );
00652   wkbPosition += sizeof( int );
00653 
00654   QList<QgsPoint>::const_iterator iter;
00655   for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter )
00656   {
00657     x = iter->x();
00658     y = iter->y();
00659     memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) );
00660     wkbPosition += sizeof( double );
00661     memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) );
00662     wkbPosition += sizeof( double );
00663   }
00664   return 0;
00665 }
00666 
00667 int QgsGml::getRingWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& ringCoordinates ) const
00668 {
00669   int wkbSize = sizeof( int ) + ringCoordinates.size() * 2 * sizeof( double );
00670   *size = wkbSize;
00671   *wkb = new unsigned char[wkbSize];
00672   int wkbPosition = 0; //current offset from wkb beginning (in bytes)
00673   double x, y;
00674   int nPoints = ringCoordinates.size();
00675   memcpy( &( *wkb )[wkbPosition], &nPoints, sizeof( int ) );
00676   wkbPosition += sizeof( int );
00677 
00678   QList<QgsPoint>::const_iterator iter;
00679   for ( iter = ringCoordinates.begin(); iter != ringCoordinates.end(); ++iter )
00680   {
00681     x = iter->x();
00682     y = iter->y();
00683     memcpy( &( *wkb )[wkbPosition], &x, sizeof( double ) );
00684     wkbPosition += sizeof( double );
00685     memcpy( &( *wkb )[wkbPosition], &y, sizeof( double ) );
00686     wkbPosition += sizeof( double );
00687   }
00688   return 0;
00689 }
00690 
00691 int QgsGml::createMultiLineFromFragments()
00692 {
00693   mCurrentWKBSize = 0;
00694   mCurrentWKBSize += 1 + 2 * sizeof( int );
00695   mCurrentWKBSize += totalWKBFragmentSize();
00696 
00697   mCurrentWKB = new unsigned char[mCurrentWKBSize];
00698   int pos = 0;
00699   QGis::WkbType type = QGis::WKBMultiLineString;
00700   int numLines = mCurrentWKBFragments.begin()->size();
00701   //add endian
00702   memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
00703   pos += 1;
00704   memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
00705   pos += sizeof( int );
00706   memcpy( &( mCurrentWKB[pos] ), &numLines, sizeof( int ) );
00707   pos += sizeof( int );
00708   QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
00709   QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
00710 
00711   //copy (and delete) all the wkb fragments
00712   for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
00713   {
00714     memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
00715     pos += *sizeIt;
00716     delete[] *wkbIt;
00717   }
00718 
00719   mCurrentWKBFragments.clear();
00720   mCurrentWKBFragmentSizes.clear();
00721   *mWkbType = QGis::WKBMultiLineString;
00722   return 0;
00723 }
00724 
00725 int QgsGml::createMultiPointFromFragments()
00726 {
00727   mCurrentWKBSize = 0;
00728   mCurrentWKBSize += 1 + 2 * sizeof( int );
00729   mCurrentWKBSize += totalWKBFragmentSize();
00730   mCurrentWKB = new unsigned char[mCurrentWKBSize];
00731 
00732   int pos = 0;
00733   QGis::WkbType type = QGis::WKBMultiPoint;
00734   int numPoints = mCurrentWKBFragments.begin()->size();
00735 
00736   memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
00737   pos += 1;
00738   memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
00739   pos += sizeof( int );
00740   memcpy( &( mCurrentWKB[pos] ), &numPoints, sizeof( int ) );
00741   pos += sizeof( int );
00742 
00743   QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
00744   QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
00745 
00746   for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
00747   {
00748     memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
00749     pos += *sizeIt;
00750     delete[] *wkbIt;
00751   }
00752 
00753   mCurrentWKBFragments.clear();
00754   mCurrentWKBFragmentSizes.clear();
00755   *mWkbType = QGis::WKBMultiPoint;
00756   return 0;
00757 }
00758 
00759 
00760 int QgsGml::createPolygonFromFragments()
00761 {
00762   mCurrentWKBSize = 0;
00763   mCurrentWKBSize += 1 + 2 * sizeof( int );
00764   mCurrentWKBSize += totalWKBFragmentSize();
00765 
00766   mCurrentWKB = new unsigned char[mCurrentWKBSize];
00767   int pos = 0;
00768   QGis::WkbType type = QGis::WKBPolygon;
00769   int numRings = mCurrentWKBFragments.begin()->size();
00770   memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
00771   pos += 1;
00772   memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
00773   pos += sizeof( int );
00774   memcpy( &( mCurrentWKB[pos] ), &numRings, sizeof( int ) );
00775   pos += sizeof( int );
00776 
00777   QList<unsigned char*>::iterator wkbIt = mCurrentWKBFragments.begin()->begin();
00778   QList<int>::iterator sizeIt = mCurrentWKBFragmentSizes.begin()->begin();
00779   for ( ; wkbIt != mCurrentWKBFragments.begin()->end(); ++wkbIt, ++sizeIt )
00780   {
00781     memcpy( &( mCurrentWKB[pos] ), *wkbIt, *sizeIt );
00782     pos += *sizeIt;
00783     delete[] *wkbIt;
00784   }
00785 
00786   mCurrentWKBFragments.clear();
00787   mCurrentWKBFragmentSizes.clear();
00788   *mWkbType = QGis::WKBPolygon;
00789   return 0;
00790 }
00791 
00792 int QgsGml::createMultiPolygonFromFragments()
00793 {
00794   mCurrentWKBSize = 0;
00795   mCurrentWKBSize += 1 + 2 * sizeof( int );
00796   mCurrentWKBSize += totalWKBFragmentSize();
00797   mCurrentWKBSize += mCurrentWKBFragments.size() * ( 1 + 2 * sizeof( int ) ); //fragments are just the rings
00798 
00799   mCurrentWKB = new unsigned char[mCurrentWKBSize];
00800   int pos = 0;
00801   QGis::WkbType type = QGis::WKBMultiPolygon;
00802   QGis::WkbType polygonType = QGis::WKBPolygon;
00803   int numPolys = mCurrentWKBFragments.size();
00804   int numRings;
00805   memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
00806   pos += 1;
00807   memcpy( &( mCurrentWKB[pos] ), &type, sizeof( int ) );
00808   pos += sizeof( int );
00809   memcpy( &( mCurrentWKB[pos] ), &numPolys, sizeof( int ) );
00810   pos += sizeof( int );
00811 
00812   //have outer and inner iterators
00813   QList< QList<unsigned char*> >::iterator outerWkbIt;
00814   QList< QList<int> >::iterator outerSizeIt;
00815   QList< unsigned char* >::iterator innerWkbIt;
00816   QList< int >::iterator innerSizeIt;
00817 
00818   outerWkbIt = mCurrentWKBFragments.begin();
00819   outerSizeIt = mCurrentWKBFragmentSizes.begin();
00820 
00821   for ( ; outerWkbIt != mCurrentWKBFragments.end(); ++outerWkbIt, ++outerSizeIt )
00822   {
00823     //new polygon
00824     memcpy( &( mCurrentWKB[pos] ), &mEndian, 1 );
00825     pos += 1;
00826     memcpy( &( mCurrentWKB[pos] ), &polygonType, sizeof( int ) );
00827     pos += sizeof( int );
00828     numRings = outerWkbIt->size();
00829     memcpy( &( mCurrentWKB[pos] ), &numRings, sizeof( int ) );
00830     pos += sizeof( int );
00831 
00832     innerWkbIt = outerWkbIt->begin();
00833     innerSizeIt = outerSizeIt->begin();
00834     for ( ; innerWkbIt != outerWkbIt->end(); ++innerWkbIt, ++innerSizeIt )
00835     {
00836       memcpy( &( mCurrentWKB[pos] ), *innerWkbIt, *innerSizeIt );
00837       pos += *innerSizeIt;
00838       delete[] *innerWkbIt;
00839     }
00840   }
00841 
00842   mCurrentWKBFragments.clear();
00843   mCurrentWKBFragmentSizes.clear();
00844   *mWkbType = QGis::WKBMultiPolygon;
00845   return 0;
00846 }
00847 
00848 int QgsGml::totalWKBFragmentSize() const
00849 {
00850   int result = 0;
00851   foreach ( const QList<int> &list, mCurrentWKBFragmentSizes )
00852   {
00853     foreach ( int i, list )
00854     {
00855       result += i;
00856     }
00857   }
00858   return result;
00859 }
00860 
00861 void QgsGml::calculateExtentFromFeatures()
00862 {
00863   if ( mFeatures.size() < 1 )
00864   {
00865     return;
00866   }
00867 
00868   QgsFeature* currentFeature = 0;
00869   QgsGeometry* currentGeometry = 0;
00870   bool bboxInitialised = false; //gets true once bbox has been set to the first geometry
00871 
00872   for ( int i = 0; i < mFeatures.size(); ++i )
00873   {
00874     currentFeature = mFeatures[i];
00875     if ( !currentFeature )
00876     {
00877       continue;
00878     }
00879     currentGeometry = currentFeature->geometry();
00880     if ( currentGeometry )
00881     {
00882       if ( !bboxInitialised )
00883       {
00884         mExtent = currentGeometry->boundingBox();
00885         bboxInitialised = true;
00886       }
00887       else
00888       {
00889         mExtent.unionRect( currentGeometry->boundingBox() );
00890       }
00891     }
00892   }
00893 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines