|
QGIS API Documentation
master-59fd5e0
|
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 }