|
Quantum GIS API Documentation
master-7dce617
|
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 }