|
QGIS API Documentation
master-3f58142
|
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 }