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