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