|
Quantum GIS API Documentation
master-693a1fe
|
00001 /*************************************************************************** 00002 qgsgeometry.cpp - Geometry (stored as Open Geospatial Consortium WKB) 00003 ------------------------------------------------------------------- 00004 Date : 02 May 2005 00005 Copyright : (C) 2005 by Brendan Morley 00006 email : morb at ozemail dot com dot au 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 00016 #include <limits> 00017 #include <cstdarg> 00018 #include <cstdio> 00019 #include <cmath> 00020 00021 #include "qgis.h" 00022 #include "qgsgeometry.h" 00023 #include "qgsapplication.h" 00024 #include "qgslogger.h" 00025 #include "qgsmessagelog.h" 00026 #include "qgspoint.h" 00027 #include "qgsrectangle.h" 00028 00029 #include "qgsmaplayerregistry.h" 00030 #include "qgsvectorlayer.h" 00031 #include "qgsproject.h" 00032 #include "qgsmessagelog.h" 00033 #include "qgsgeometryvalidator.h" 00034 00035 #ifndef Q_WS_WIN 00036 #include <netinet/in.h> 00037 #else 00038 #include <winsock.h> 00039 #endif 00040 00041 #define DEFAULT_QUADRANT_SEGMENTS 8 00042 00043 #define CATCH_GEOS(r) \ 00044 catch (GEOSException &e) \ 00045 { \ 00046 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr("GEOS") ); \ 00047 return r; \ 00048 } 00049 00050 class GEOSException 00051 { 00052 public: 00053 GEOSException( QString theMsg ) 00054 { 00055 if ( theMsg == "Unknown exception thrown" && lastMsg.isNull() ) 00056 { 00057 msg = theMsg; 00058 } 00059 else 00060 { 00061 msg = theMsg; 00062 lastMsg = msg; 00063 } 00064 } 00065 00066 // copy constructor 00067 GEOSException( const GEOSException &rhs ) 00068 { 00069 *this = rhs; 00070 } 00071 00072 ~GEOSException() 00073 { 00074 if ( lastMsg == msg ) 00075 lastMsg = QString::null; 00076 } 00077 00078 QString what() 00079 { 00080 return msg; 00081 } 00082 00083 private: 00084 QString msg; 00085 static QString lastMsg; 00086 }; 00087 00088 QString GEOSException::lastMsg; 00089 00090 static void throwGEOSException( const char *fmt, ... ) 00091 { 00092 va_list ap; 00093 char buffer[1024]; 00094 00095 va_start( ap, fmt ); 00096 vsnprintf( buffer, sizeof buffer, fmt, ap ); 00097 va_end( ap ); 00098 00099 QgsDebugMsg( QString( "GEOS exception: %1" ).arg( buffer ) ); 00100 00101 throw GEOSException( QString::fromUtf8( buffer ) ); 00102 } 00103 00104 static void printGEOSNotice( const char *fmt, ... ) 00105 { 00106 #if defined(QGISDEBUG) 00107 va_list ap; 00108 char buffer[1024]; 00109 00110 va_start( ap, fmt ); 00111 vsnprintf( buffer, sizeof buffer, fmt, ap ); 00112 va_end( ap ); 00113 00114 QgsDebugMsg( QString( "GEOS notice: %1" ).arg( QString::fromUtf8( buffer ) ) ); 00115 #else 00116 Q_UNUSED( fmt ); 00117 #endif 00118 } 00119 00120 class GEOSInit 00121 { 00122 public: 00123 GEOSInit() 00124 { 00125 initGEOS( printGEOSNotice, throwGEOSException ); 00126 } 00127 00128 ~GEOSInit() 00129 { 00130 finishGEOS(); 00131 } 00132 }; 00133 00134 static GEOSInit geosinit; 00135 00136 00137 #if defined(GEOS_VERSION_MAJOR) && (GEOS_VERSION_MAJOR<3) 00138 #define GEOSGeom_getCoordSeq(g) GEOSGeom_getCoordSeq( (GEOSGeometry *) g ) 00139 #define GEOSGetExteriorRing(g) GEOSGetExteriorRing( (GEOSGeometry *)g ) 00140 #define GEOSGetNumInteriorRings(g) GEOSGetNumInteriorRings( (GEOSGeometry *)g ) 00141 #define GEOSGetInteriorRingN(g,i) GEOSGetInteriorRingN( (GEOSGeometry *)g, i ) 00142 #define GEOSDisjoint(g0,g1) GEOSDisjoint( (GEOSGeometry *)g0, (GEOSGeometry*)g1 ) 00143 #define GEOSIntersection(g0,g1) GEOSIntersection( (GEOSGeometry*) g0, (GEOSGeometry*)g1 ) 00144 #define GEOSBuffer(g, d, s) GEOSBuffer( (GEOSGeometry*) g, d, s ) 00145 #define GEOSArea(g, a) GEOSArea( (GEOSGeometry*) g, a ) 00146 #define GEOSSimplify(g, t) GEOSSimplify( (GEOSGeometry*) g, t ) 00147 #define GEOSGetCentroid(g) GEOSGetCentroid( (GEOSGeometry*) g ) 00148 00149 #define GEOSCoordSeq_getSize(cs,n) GEOSCoordSeq_getSize( (GEOSCoordSequence *) cs, n ) 00150 #define GEOSCoordSeq_getX(cs,i,x) GEOSCoordSeq_getX( (GEOSCoordSequence *)cs, i, x ) 00151 #define GEOSCoordSeq_getY(cs,i,y) GEOSCoordSeq_getY( (GEOSCoordSequence *)cs, i, y ) 00152 00153 static GEOSGeometry *createGeosCollection( int typeId, QVector<GEOSGeometry*> geoms ); 00154 00155 static GEOSGeometry *cloneGeosGeom( const GEOSGeometry *geom ) 00156 { 00157 // for GEOS < 3.0 we have own cloning function 00158 // because when cloning multipart geometries they're copied into more general geometry collection instance 00159 int type = GEOSGeomTypeId(( GEOSGeometry * ) geom ); 00160 00161 if ( type == GEOS_MULTIPOINT || type == GEOS_MULTILINESTRING || type == GEOS_MULTIPOLYGON ) 00162 { 00163 QVector<GEOSGeometry *> geoms; 00164 00165 try 00166 { 00167 00168 for ( int i = 0; i < GEOSGetNumGeometries(( GEOSGeometry * )geom ); ++i ) 00169 geoms << GEOSGeom_clone(( GEOSGeometry * ) GEOSGetGeometryN(( GEOSGeometry * ) geom, i ) ); 00170 00171 return createGeosCollection( type, geoms ); 00172 } 00173 catch ( GEOSException &e ) 00174 { 00175 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00176 for ( int i = 0; i < geoms.count(); i++ ) 00177 GEOSGeom_destroy( geoms[i] ); 00178 00179 return 0; 00180 } 00181 } 00182 else 00183 { 00184 return GEOSGeom_clone(( GEOSGeometry * ) geom ); 00185 } 00186 } 00187 00188 #define GEOSGeom_clone(g) cloneGeosGeom(g) 00189 #endif 00190 00191 QgsGeometry::QgsGeometry() 00192 : mGeometry( 0 ) 00193 , mGeometrySize( 0 ) 00194 , mGeos( 0 ) 00195 , mDirtyWkb( false ) 00196 , mDirtyGeos( false ) 00197 { 00198 } 00199 00200 QgsGeometry::QgsGeometry( QgsGeometry const & rhs ) 00201 : mGeometry( 0 ) 00202 , mGeometrySize( rhs.mGeometrySize ) 00203 , mDirtyWkb( rhs.mDirtyWkb ) 00204 , mDirtyGeos( rhs.mDirtyGeos ) 00205 { 00206 if ( mGeometrySize && rhs.mGeometry ) 00207 { 00208 mGeometry = new unsigned char[mGeometrySize]; 00209 memcpy( mGeometry, rhs.mGeometry, mGeometrySize ); 00210 } 00211 00212 // deep-copy the GEOS Geometry if appropriate 00213 if ( rhs.mGeos ) 00214 { 00215 mGeos = GEOSGeom_clone( rhs.mGeos ); 00216 } 00217 else 00218 { 00219 mGeos = 0; 00220 } 00221 } 00222 00224 QgsGeometry::~QgsGeometry() 00225 { 00226 if ( mGeometry ) 00227 { 00228 delete [] mGeometry; 00229 } 00230 00231 if ( mGeos ) 00232 { 00233 GEOSGeom_destroy( mGeos ); 00234 } 00235 } 00236 00237 static unsigned int getNumGeosPoints( const GEOSGeometry *geom ) 00238 { 00239 unsigned int n; 00240 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( geom ); 00241 GEOSCoordSeq_getSize( cs, &n ); 00242 return n; 00243 } 00244 00245 static GEOSGeometry *createGeosPoint( const QgsPoint &point ) 00246 { 00247 GEOSCoordSequence *coord = GEOSCoordSeq_create( 1, 2 ); 00248 GEOSCoordSeq_setX( coord, 0, point.x() ); 00249 GEOSCoordSeq_setY( coord, 0, point.y() ); 00250 return GEOSGeom_createPoint( coord ); 00251 } 00252 00253 static GEOSCoordSequence *createGeosCoordSequence( const QgsPolyline& points ) 00254 { 00255 GEOSCoordSequence *coord = 0; 00256 00257 try 00258 { 00259 coord = GEOSCoordSeq_create( points.count(), 2 ); 00260 int i; 00261 for ( i = 0; i < points.count(); i++ ) 00262 { 00263 GEOSCoordSeq_setX( coord, i, points[i].x() ); 00264 GEOSCoordSeq_setY( coord, i, points[i].y() ); 00265 } 00266 return coord; 00267 } 00268 catch ( GEOSException &e ) 00269 { 00270 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00271 /*if ( coord ) 00272 GEOSCoordSeq_destroy( coord );*/ 00273 throw; 00274 } 00275 } 00276 00277 static GEOSGeometry *createGeosCollection( int typeId, QVector<GEOSGeometry*> geoms ) 00278 { 00279 GEOSGeometry **geomarr = new GEOSGeometry*[ geoms.size()]; 00280 if ( !geomarr ) 00281 return 0; 00282 00283 for ( int i = 0; i < geoms.size(); i++ ) 00284 geomarr[i] = geoms[i]; 00285 00286 GEOSGeometry *geom = 0; 00287 00288 try 00289 { 00290 geom = GEOSGeom_createCollection( typeId, geomarr, geoms.size() ); 00291 } 00292 catch ( GEOSException &e ) 00293 { 00294 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00295 } 00296 00297 delete [] geomarr; 00298 00299 return geom; 00300 } 00301 00302 static GEOSGeometry *createGeosLineString( const QgsPolyline& polyline ) 00303 { 00304 GEOSCoordSequence *coord = 0; 00305 00306 try 00307 { 00308 coord = createGeosCoordSequence( polyline ); 00309 return GEOSGeom_createLineString( coord ); 00310 } 00311 catch ( GEOSException &e ) 00312 { 00313 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00314 //MH: for strange reasons, geos3 crashes when removing the coordinate sequence 00315 //if ( coord ) 00316 //GEOSCoordSeq_destroy( coord ); 00317 return 0; 00318 } 00319 } 00320 00321 static GEOSGeometry *createGeosLinearRing( const QgsPolyline& polyline ) 00322 { 00323 GEOSCoordSequence *coord = 0; 00324 00325 if ( polyline.count() == 0 ) 00326 return 0; 00327 00328 try 00329 { 00330 if ( polyline[0] != polyline[polyline.size()-1] ) 00331 { 00332 // Ring not closed 00333 QgsPolyline closed( polyline ); 00334 closed << closed[0]; 00335 coord = createGeosCoordSequence( closed ); 00336 } 00337 else 00338 { 00339 coord = createGeosCoordSequence( polyline ); 00340 } 00341 00342 return GEOSGeom_createLinearRing( coord ); 00343 } 00344 catch ( GEOSException &e ) 00345 { 00346 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00347 /* as MH has noticed ^, this crashes geos 00348 if ( coord ) 00349 GEOSCoordSeq_destroy( coord );*/ 00350 return 0; 00351 } 00352 } 00353 00354 static GEOSGeometry *createGeosPolygon( const QVector<GEOSGeometry*> &rings ) 00355 { 00356 GEOSGeometry *shell = rings[0]; 00357 GEOSGeometry **holes = NULL; 00358 00359 if ( rings.size() > 1 ) 00360 { 00361 holes = new GEOSGeometry*[ rings.size()-1 ]; 00362 if ( !holes ) 00363 return 0; 00364 00365 for ( int i = 0; i < rings.size() - 1; i++ ) 00366 holes[i] = rings[i+1]; 00367 } 00368 00369 GEOSGeometry *geom = GEOSGeom_createPolygon( shell, holes, rings.size() - 1 ); 00370 00371 if ( holes ) 00372 delete [] holes; 00373 00374 return geom; 00375 } 00376 00377 static GEOSGeometry *createGeosPolygon( GEOSGeometry *shell ) 00378 { 00379 return createGeosPolygon( QVector<GEOSGeometry*>() << shell ); 00380 } 00381 00382 static GEOSGeometry *createGeosPolygon( const QgsPolygon& polygon ) 00383 { 00384 if ( polygon.count() == 0 ) 00385 return 0; 00386 00387 QVector<GEOSGeometry *> geoms; 00388 00389 try 00390 { 00391 for ( int i = 0; i < polygon.count(); i++ ) 00392 geoms << createGeosLinearRing( polygon[i] ); 00393 00394 return createGeosPolygon( geoms ); 00395 } 00396 catch ( GEOSException &e ) 00397 { 00398 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00399 for ( int i = 0; i < geoms.count(); i++ ) 00400 GEOSGeom_destroy( geoms[i] ); 00401 return 0; 00402 } 00403 } 00404 00405 static QgsGeometry *fromGeosGeom( GEOSGeometry *geom ) 00406 { 00407 if ( !geom ) 00408 return 0; 00409 00410 QgsGeometry* g = new QgsGeometry; 00411 g->fromGeos( geom ); 00412 return g; 00413 } 00414 00415 QgsGeometry* QgsGeometry::fromWkt( QString wkt ) 00416 { 00417 try 00418 { 00419 #if defined(GEOS_VERSION_MAJOR) && (GEOS_VERSION_MAJOR>=3) 00420 GEOSWKTReader *reader = GEOSWKTReader_create(); 00421 QgsGeometry *g = fromGeosGeom( GEOSWKTReader_read( reader, wkt.toLocal8Bit().data() ) ); 00422 GEOSWKTReader_destroy( reader ); 00423 return g; 00424 #else 00425 return fromGeosGeom( GEOSGeomFromWKT( wkt.toLocal8Bit().data() ) ); 00426 #endif 00427 } 00428 catch ( GEOSException &e ) 00429 { 00430 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00431 return 0; 00432 } 00433 } 00434 00435 QgsGeometry* QgsGeometry::fromPoint( const QgsPoint& point ) 00436 { 00437 return fromGeosGeom( createGeosPoint( point ) ); 00438 } 00439 00440 QgsGeometry* QgsGeometry::fromPolyline( const QgsPolyline& polyline ) 00441 { 00442 return fromGeosGeom( createGeosLineString( polyline ) ); 00443 } 00444 00445 QgsGeometry* QgsGeometry::fromPolygon( const QgsPolygon& polygon ) 00446 { 00447 return fromGeosGeom( createGeosPolygon( polygon ) ); 00448 } 00449 00450 QgsGeometry* QgsGeometry::fromMultiPoint( const QgsMultiPoint& multipoint ) 00451 { 00452 QVector<GEOSGeometry *> geoms; 00453 00454 try 00455 { 00456 for ( int i = 0; i < multipoint.size(); ++i ) 00457 { 00458 geoms << createGeosPoint( multipoint[i] ); 00459 } 00460 00461 return fromGeosGeom( createGeosCollection( GEOS_MULTIPOINT, geoms ) ); 00462 } 00463 catch ( GEOSException &e ) 00464 { 00465 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00466 00467 for ( int i = 0; i < geoms.size(); ++i ) 00468 GEOSGeom_destroy( geoms[i] ); 00469 00470 return 0; 00471 } 00472 } 00473 00474 QgsGeometry* QgsGeometry::fromMultiPolyline( const QgsMultiPolyline& multiline ) 00475 { 00476 QVector<GEOSGeometry *> geoms; 00477 00478 try 00479 { 00480 for ( int i = 0; i < multiline.count(); i++ ) 00481 geoms << createGeosLineString( multiline[i] ); 00482 00483 return fromGeosGeom( createGeosCollection( GEOS_MULTILINESTRING, geoms ) ); 00484 } 00485 catch ( GEOSException &e ) 00486 { 00487 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00488 00489 for ( int i = 0; i < geoms.count(); i++ ) 00490 GEOSGeom_destroy( geoms[i] ); 00491 00492 return 0; 00493 } 00494 } 00495 00496 QgsGeometry* QgsGeometry::fromMultiPolygon( const QgsMultiPolygon& multipoly ) 00497 { 00498 if ( multipoly.count() == 0 ) 00499 return 0; 00500 00501 QVector<GEOSGeometry *> geoms; 00502 00503 try 00504 { 00505 for ( int i = 0; i < multipoly.count(); i++ ) 00506 geoms << createGeosPolygon( multipoly[i] ); 00507 00508 return fromGeosGeom( createGeosCollection( GEOS_MULTIPOLYGON, geoms ) ); 00509 } 00510 catch ( GEOSException &e ) 00511 { 00512 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 00513 00514 for ( int i = 0; i < geoms.count(); i++ ) 00515 GEOSGeom_destroy( geoms[i] ); 00516 00517 return 0; 00518 } 00519 } 00520 00521 QgsGeometry* QgsGeometry::fromRect( const QgsRectangle& rect ) 00522 { 00523 QgsPolyline ring; 00524 ring.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) ); 00525 ring.append( QgsPoint( rect.xMaximum(), rect.yMinimum() ) ); 00526 ring.append( QgsPoint( rect.xMaximum(), rect.yMaximum() ) ); 00527 ring.append( QgsPoint( rect.xMinimum(), rect.yMaximum() ) ); 00528 ring.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) ); 00529 00530 QgsPolygon polygon; 00531 polygon.append( ring ); 00532 00533 return fromPolygon( polygon ); 00534 } 00535 00536 00537 QgsGeometry & QgsGeometry::operator=( QgsGeometry const & rhs ) 00538 { 00539 if ( &rhs == this ) 00540 { 00541 return *this; 00542 } 00543 00544 // remove old geometry if it exists 00545 if ( mGeometry ) 00546 { 00547 delete [] mGeometry; 00548 mGeometry = 0; 00549 } 00550 00551 mGeometrySize = rhs.mGeometrySize; 00552 00553 // deep-copy the GEOS Geometry if appropriate 00554 GEOSGeom_destroy( mGeos ); 00555 mGeos = rhs.mGeos ? GEOSGeom_clone( rhs.mGeos ) : 0; 00556 00557 mDirtyGeos = rhs.mDirtyGeos; 00558 mDirtyWkb = rhs.mDirtyWkb; 00559 00560 if ( mGeometrySize && rhs.mGeometry ) 00561 { 00562 mGeometry = new unsigned char[mGeometrySize]; 00563 memcpy( mGeometry, rhs.mGeometry, mGeometrySize ); 00564 } 00565 00566 return *this; 00567 } // QgsGeometry::operator=( QgsGeometry const & rhs ) 00568 00569 00570 void QgsGeometry::fromWkb( unsigned char * wkb, size_t length ) 00571 { 00572 // delete any existing WKB geometry before assigning new one 00573 if ( mGeometry ) 00574 { 00575 delete [] mGeometry; 00576 mGeometry = 0; 00577 } 00578 if ( mGeos ) 00579 { 00580 GEOSGeom_destroy( mGeos ); 00581 mGeos = 0; 00582 } 00583 00584 mGeometry = wkb; 00585 mGeometrySize = length; 00586 00587 mDirtyWkb = false; 00588 mDirtyGeos = true; 00589 } 00590 00591 unsigned char * QgsGeometry::asWkb() 00592 { 00593 if ( mDirtyWkb ) 00594 { 00595 // convert from GEOS 00596 exportGeosToWkb(); 00597 } 00598 00599 return mGeometry; 00600 } 00601 00602 size_t QgsGeometry::wkbSize() 00603 { 00604 if ( mDirtyWkb ) 00605 { 00606 exportGeosToWkb(); 00607 } 00608 00609 return mGeometrySize; 00610 } 00611 00612 GEOSGeometry* QgsGeometry::asGeos() 00613 { 00614 if ( mDirtyGeos ) 00615 { 00616 if ( !exportWkbToGeos() ) 00617 { 00618 return 0; 00619 } 00620 } 00621 return mGeos; 00622 } 00623 00624 00625 QGis::WkbType QgsGeometry::wkbType() 00626 { 00627 unsigned char *geom = asWkb(); // ensure that wkb representation exists 00628 if ( geom && wkbSize() >= 5 ) 00629 { 00630 unsigned int wkbType; 00631 memcpy( &wkbType, ( geom + 1 ), sizeof( wkbType ) ); 00632 return ( QGis::WkbType ) wkbType; 00633 } 00634 else 00635 { 00636 return QGis::WKBUnknown; 00637 } 00638 } 00639 00640 00641 QGis::GeometryType QgsGeometry::type() 00642 { 00643 if ( mDirtyWkb ) 00644 { 00645 // convert from GEOS 00646 exportGeosToWkb(); 00647 } 00648 00649 switch ( wkbType() ) 00650 { 00651 case QGis::WKBPoint: 00652 case QGis::WKBPoint25D: 00653 case QGis::WKBMultiPoint: 00654 case QGis::WKBMultiPoint25D: 00655 return QGis::Point; 00656 00657 case QGis::WKBLineString: 00658 case QGis::WKBLineString25D: 00659 case QGis::WKBMultiLineString: 00660 case QGis::WKBMultiLineString25D: 00661 return QGis::Line; 00662 00663 case QGis::WKBPolygon: 00664 case QGis::WKBPolygon25D: 00665 case QGis::WKBMultiPolygon: 00666 case QGis::WKBMultiPolygon25D: 00667 return QGis::Polygon; 00668 00669 default: 00670 return QGis::UnknownGeometry; 00671 } 00672 } 00673 00674 bool QgsGeometry::isMultipart() 00675 { 00676 if ( mDirtyWkb ) 00677 { 00678 // convert from GEOS 00679 exportGeosToWkb(); 00680 } 00681 00682 QGis::WkbType type = wkbType(); 00683 if ( type == QGis::WKBMultiPoint || 00684 type == QGis::WKBMultiPoint25D || 00685 type == QGis::WKBMultiLineString || 00686 type == QGis::WKBMultiLineString25D || 00687 type == QGis::WKBMultiPolygon || 00688 type == QGis::WKBMultiPolygon25D ) 00689 return true; 00690 00691 return false; 00692 } 00693 00694 00695 void QgsGeometry::fromGeos( GEOSGeometry* geos ) 00696 { 00697 // TODO - make this more heap-friendly 00698 00699 if ( mGeos ) 00700 { 00701 GEOSGeom_destroy( mGeos ); 00702 mGeos = 0; 00703 } 00704 if ( mGeometry ) 00705 { 00706 delete [] mGeometry; 00707 mGeometry = 0; 00708 } 00709 00710 mGeos = geos; 00711 00712 mDirtyWkb = true; 00713 mDirtyGeos = false; 00714 } 00715 00716 QgsPoint QgsGeometry::closestVertex( const QgsPoint& point, int& atVertex, int& beforeVertex, int& afterVertex, double& sqrDist ) 00717 { 00718 // TODO: implement with GEOS 00719 if ( mDirtyWkb ) 00720 { 00721 exportGeosToWkb(); 00722 } 00723 00724 if ( !mGeometry ) 00725 { 00726 QgsDebugMsg( "WKB geometry not available!" ); 00727 return QgsPoint( 0, 0 ); 00728 } 00729 00730 int vertexnr = -1; 00731 int vertexcounter = 0; 00732 QGis::WkbType wkbType; 00733 double actdist = std::numeric_limits<double>::max(); 00734 double x = 0; 00735 double y = 0; 00736 double *tempx, *tempy; 00737 memcpy( &wkbType, ( mGeometry + 1 ), sizeof( int ) ); 00738 beforeVertex = -1; 00739 afterVertex = -1; 00740 bool hasZValue = false; 00741 00742 switch ( wkbType ) 00743 { 00744 case QGis::WKBPoint25D: 00745 case QGis::WKBPoint: 00746 { 00747 x = *(( double * )( mGeometry + 5 ) ); 00748 y = *(( double * )( mGeometry + 5 + sizeof( double ) ) ); 00749 actdist = point.sqrDist( x, y ); 00750 vertexnr = 0; 00751 break; 00752 } 00753 case QGis::WKBLineString25D: 00754 hasZValue = true; 00755 00756 // fall-through 00757 00758 case QGis::WKBLineString: 00759 { 00760 unsigned char* ptr = mGeometry + 5; 00761 int* npoints = ( int* )ptr; 00762 ptr += sizeof( int ); 00763 for ( int index = 0; index < *npoints; ++index ) 00764 { 00765 tempx = ( double* )ptr; 00766 ptr += sizeof( double ); 00767 tempy = ( double* )ptr; 00768 if ( point.sqrDist( *tempx, *tempy ) < actdist ) 00769 { 00770 x = *tempx; 00771 y = *tempy; 00772 actdist = point.sqrDist( *tempx, *tempy ); 00773 vertexnr = index; 00774 if ( index == 0 )//assign the rubber band indices 00775 { 00776 beforeVertex = -1; 00777 } 00778 else 00779 { 00780 beforeVertex = index - 1; 00781 } 00782 if ( index == ( *npoints - 1 ) ) 00783 { 00784 afterVertex = -1; 00785 } 00786 else 00787 { 00788 afterVertex = index + 1; 00789 } 00790 } 00791 ptr += sizeof( double ); 00792 if ( hasZValue ) //skip z-coordinate for 25D geometries 00793 { 00794 ptr += sizeof( double ); 00795 } 00796 } 00797 break; 00798 } 00799 case QGis::WKBPolygon25D: 00800 hasZValue = true; 00801 case QGis::WKBPolygon: 00802 { 00803 int* nrings = ( int* )( mGeometry + 5 ); 00804 int* npoints; 00805 unsigned char* ptr = mGeometry + 9; 00806 for ( int index = 0; index < *nrings; ++index ) 00807 { 00808 npoints = ( int* )ptr; 00809 ptr += sizeof( int ); 00810 for ( int index2 = 0; index2 < *npoints; ++index2 ) 00811 { 00812 tempx = ( double* )ptr; 00813 ptr += sizeof( double ); 00814 tempy = ( double* )ptr; 00815 if ( point.sqrDist( *tempx, *tempy ) < actdist ) 00816 { 00817 x = *tempx; 00818 y = *tempy; 00819 actdist = point.sqrDist( *tempx, *tempy ); 00820 vertexnr = vertexcounter; 00821 //assign the rubber band indices 00822 if ( index2 == 0 ) 00823 { 00824 beforeVertex = vertexcounter + ( *npoints - 2 ); 00825 afterVertex = vertexcounter + 1; 00826 } 00827 else if ( index2 == ( *npoints - 1 ) ) 00828 { 00829 beforeVertex = vertexcounter - 1; 00830 afterVertex = vertexcounter - ( *npoints - 2 ); 00831 } 00832 else 00833 { 00834 beforeVertex = vertexcounter - 1; 00835 afterVertex = vertexcounter + 1; 00836 } 00837 } 00838 ptr += sizeof( double ); 00839 if ( hasZValue ) //skip z-coordinate for 25D geometries 00840 { 00841 ptr += sizeof( double ); 00842 } 00843 ++vertexcounter; 00844 } 00845 } 00846 break; 00847 } 00848 case QGis::WKBMultiPoint25D: 00849 hasZValue = true; 00850 case QGis::WKBMultiPoint: 00851 { 00852 unsigned char* ptr = mGeometry + 5; 00853 int* npoints = ( int* )ptr; 00854 ptr += sizeof( int ); 00855 for ( int index = 0; index < *npoints; ++index ) 00856 { 00857 ptr += ( 1 + sizeof( int ) ); //skip endian and point type 00858 tempx = ( double* )ptr; 00859 tempy = ( double* )( ptr + sizeof( double ) ); 00860 if ( point.sqrDist( *tempx, *tempy ) < actdist ) 00861 { 00862 x = *tempx; 00863 y = *tempy; 00864 actdist = point.sqrDist( *tempx, *tempy ); 00865 vertexnr = index; 00866 } 00867 ptr += ( 2 * sizeof( double ) ); 00868 if ( hasZValue ) //skip z-coordinate for 25D geometries 00869 { 00870 ptr += sizeof( double ); 00871 } 00872 } 00873 break; 00874 } 00875 case QGis::WKBMultiLineString25D: 00876 hasZValue = true; 00877 case QGis::WKBMultiLineString: 00878 { 00879 unsigned char* ptr = mGeometry + 5; 00880 int* nlines = ( int* )ptr; 00881 int* npoints = 0; 00882 ptr += sizeof( int ); 00883 for ( int index = 0; index < *nlines; ++index ) 00884 { 00885 ptr += ( sizeof( int ) + 1 ); 00886 npoints = ( int* )ptr; 00887 ptr += sizeof( int ); 00888 for ( int index2 = 0; index2 < *npoints; ++index2 ) 00889 { 00890 tempx = ( double* )ptr; 00891 ptr += sizeof( double ); 00892 tempy = ( double* )ptr; 00893 ptr += sizeof( double ); 00894 if ( point.sqrDist( *tempx, *tempy ) < actdist ) 00895 { 00896 x = *tempx; 00897 y = *tempy; 00898 actdist = point.sqrDist( *tempx, *tempy ); 00899 vertexnr = vertexcounter; 00900 00901 if ( index2 == 0 )//assign the rubber band indices 00902 { 00903 beforeVertex = -1; 00904 } 00905 else 00906 { 00907 beforeVertex = vertexnr - 1; 00908 } 00909 if ( index2 == ( *npoints ) - 1 ) 00910 { 00911 afterVertex = -1; 00912 } 00913 else 00914 { 00915 afterVertex = vertexnr + 1; 00916 } 00917 } 00918 if ( hasZValue ) //skip z-coordinate for 25D geometries 00919 { 00920 ptr += sizeof( double ); 00921 } 00922 ++vertexcounter; 00923 } 00924 } 00925 break; 00926 } 00927 case QGis::WKBMultiPolygon25D: 00928 hasZValue = true; 00929 case QGis::WKBMultiPolygon: 00930 { 00931 unsigned char* ptr = mGeometry + 5; 00932 int* npolys = ( int* )ptr; 00933 int* nrings; 00934 int* npoints; 00935 ptr += sizeof( int ); 00936 for ( int index = 0; index < *npolys; ++index ) 00937 { 00938 ptr += ( 1 + sizeof( int ) ); //skip endian and polygon type 00939 nrings = ( int* )ptr; 00940 ptr += sizeof( int ); 00941 for ( int index2 = 0; index2 < *nrings; ++index2 ) 00942 { 00943 npoints = ( int* )ptr; 00944 ptr += sizeof( int ); 00945 for ( int index3 = 0; index3 < *npoints; ++index3 ) 00946 { 00947 tempx = ( double* )ptr; 00948 ptr += sizeof( double ); 00949 tempy = ( double* )ptr; 00950 if ( point.sqrDist( *tempx, *tempy ) < actdist ) 00951 { 00952 x = *tempx; 00953 y = *tempy; 00954 actdist = point.sqrDist( *tempx, *tempy ); 00955 vertexnr = vertexcounter; 00956 00957 //assign the rubber band indices 00958 if ( index3 == 0 ) 00959 { 00960 beforeVertex = vertexcounter + ( *npoints - 2 ); 00961 afterVertex = vertexcounter + 1; 00962 } 00963 else if ( index3 == ( *npoints - 1 ) ) 00964 { 00965 beforeVertex = vertexcounter - 1; 00966 afterVertex = vertexcounter - ( *npoints - 2 ); 00967 } 00968 else 00969 { 00970 beforeVertex = vertexcounter - 1; 00971 afterVertex = vertexcounter + 1; 00972 } 00973 } 00974 ptr += sizeof( double ); 00975 if ( hasZValue ) //skip z-coordinate for 25D geometries 00976 { 00977 ptr += sizeof( double ); 00978 } 00979 ++vertexcounter; 00980 } 00981 } 00982 } 00983 break; 00984 } 00985 default: 00986 break; 00987 } 00988 sqrDist = actdist; 00989 atVertex = vertexnr; 00990 return QgsPoint( x, y ); 00991 } 00992 00993 00994 void QgsGeometry::adjacentVertices( int atVertex, int& beforeVertex, int& afterVertex ) 00995 { 00996 // TODO: implement with GEOS 00997 if ( mDirtyWkb ) 00998 { 00999 exportGeosToWkb(); 01000 } 01001 01002 beforeVertex = -1; 01003 afterVertex = -1; 01004 01005 if ( !mGeometry ) 01006 { 01007 QgsDebugMsg( "WKB geometry not available!" ); 01008 return; 01009 } 01010 01011 int vertexcounter = 0; 01012 01013 QGis::WkbType wkbType; 01014 bool hasZValue = false; 01015 01016 memcpy( &wkbType, ( mGeometry + 1 ), sizeof( int ) ); 01017 01018 switch ( wkbType ) 01019 { 01020 case QGis::WKBPoint: 01021 { 01022 // NOOP - Points do not have adjacent verticies 01023 break; 01024 } 01025 case QGis::WKBLineString25D: 01026 case QGis::WKBLineString: 01027 { 01028 unsigned char* ptr = mGeometry + 5; 01029 int* npoints = ( int* ) ptr; 01030 01031 const int index = atVertex; 01032 01033 // assign the rubber band indices 01034 01035 if ( index == 0 ) 01036 { 01037 beforeVertex = -1; 01038 } 01039 else 01040 { 01041 beforeVertex = index - 1; 01042 } 01043 01044 if ( index == ( *npoints - 1 ) ) 01045 { 01046 afterVertex = -1; 01047 } 01048 else 01049 { 01050 afterVertex = index + 1; 01051 } 01052 01053 break; 01054 } 01055 case QGis::WKBPolygon25D: 01056 hasZValue = true; 01057 case QGis::WKBPolygon: 01058 { 01059 int* nrings = ( int* )( mGeometry + 5 ); 01060 int* npoints; 01061 unsigned char* ptr = mGeometry + 9; 01062 01063 // Walk through the POLYGON WKB 01064 01065 for ( int index0 = 0; index0 < *nrings; ++index0 ) 01066 { 01067 npoints = ( int* )ptr; 01068 ptr += sizeof( int ); 01069 01070 for ( int index1 = 0; index1 < *npoints; ++index1 ) 01071 { 01072 ptr += sizeof( double ); 01073 ptr += sizeof( double ); 01074 if ( hasZValue ) //skip z-coordinate for 25D geometries 01075 { 01076 ptr += sizeof( double ); 01077 } 01078 if ( vertexcounter == atVertex ) 01079 { 01080 if ( index1 == 0 ) 01081 { 01082 beforeVertex = vertexcounter + ( *npoints - 2 ); 01083 afterVertex = vertexcounter + 1; 01084 } 01085 else if ( index1 == ( *npoints - 1 ) ) 01086 { 01087 beforeVertex = vertexcounter - 1; 01088 afterVertex = vertexcounter - ( *npoints - 2 ); 01089 } 01090 else 01091 { 01092 beforeVertex = vertexcounter - 1; 01093 afterVertex = vertexcounter + 1; 01094 } 01095 } 01096 01097 ++vertexcounter; 01098 } 01099 } 01100 break; 01101 } 01102 case QGis::WKBMultiPoint25D: 01103 case QGis::WKBMultiPoint: 01104 { 01105 // NOOP - Points do not have adjacent verticies 01106 break; 01107 } 01108 01109 case QGis::WKBMultiLineString25D: 01110 hasZValue = true; 01111 case QGis::WKBMultiLineString: 01112 { 01113 unsigned char* ptr = mGeometry + 5; 01114 int* nlines = ( int* )ptr; 01115 int* npoints = 0; 01116 ptr += sizeof( int ); 01117 01118 for ( int index0 = 0; index0 < *nlines; ++index0 ) 01119 { 01120 ptr += ( sizeof( int ) + 1 ); 01121 npoints = ( int* )ptr; 01122 ptr += sizeof( int ); 01123 01124 for ( int index1 = 0; index1 < *npoints; ++index1 ) 01125 { 01126 ptr += sizeof( double ); 01127 ptr += sizeof( double ); 01128 if ( hasZValue ) //skip z-coordinate for 25D geometries 01129 { 01130 ptr += sizeof( double ); 01131 } 01132 01133 if ( vertexcounter == atVertex ) 01134 { 01135 // Found the vertex of the linestring we were looking for. 01136 if ( index1 == 0 ) 01137 { 01138 beforeVertex = -1; 01139 } 01140 else 01141 { 01142 beforeVertex = vertexcounter - 1; 01143 } 01144 if ( index1 == ( *npoints ) - 1 ) 01145 { 01146 afterVertex = -1; 01147 } 01148 else 01149 { 01150 afterVertex = vertexcounter + 1; 01151 } 01152 } 01153 ++vertexcounter; 01154 } 01155 } 01156 break; 01157 } 01158 case QGis::WKBMultiPolygon25D: 01159 hasZValue = true; 01160 case QGis::WKBMultiPolygon: 01161 { 01162 unsigned char* ptr = mGeometry + 5; 01163 int* npolys = ( int* )ptr; 01164 int* nrings; 01165 int* npoints; 01166 ptr += sizeof( int ); 01167 01168 for ( int index0 = 0; index0 < *npolys; ++index0 ) 01169 { 01170 ptr += ( 1 + sizeof( int ) ); //skip endian and polygon type 01171 nrings = ( int* )ptr; 01172 ptr += sizeof( int ); 01173 01174 for ( int index1 = 0; index1 < *nrings; ++index1 ) 01175 { 01176 npoints = ( int* )ptr; 01177 ptr += sizeof( int ); 01178 01179 for ( int index2 = 0; index2 < *npoints; ++index2 ) 01180 { 01181 ptr += sizeof( double ); 01182 ptr += sizeof( double ); 01183 if ( hasZValue ) //skip z-coordinate for 25D geometries 01184 { 01185 ptr += sizeof( double ); 01186 } 01187 if ( vertexcounter == atVertex ) 01188 { 01189 // Found the vertex of the linear-ring of the polygon we were looking for. 01190 // assign the rubber band indices 01191 01192 if ( index2 == 0 ) 01193 { 01194 beforeVertex = vertexcounter + ( *npoints - 2 ); 01195 afterVertex = vertexcounter + 1; 01196 } 01197 else if ( index2 == ( *npoints - 1 ) ) 01198 { 01199 beforeVertex = vertexcounter - 1; 01200 afterVertex = vertexcounter - ( *npoints - 2 ); 01201 } 01202 else 01203 { 01204 beforeVertex = vertexcounter - 1; 01205 afterVertex = vertexcounter + 1; 01206 } 01207 } 01208 ++vertexcounter; 01209 } 01210 } 01211 } 01212 01213 break; 01214 } 01215 01216 default: 01217 break; 01218 } // switch (wkbType) 01219 } 01220 01221 01222 01223 bool QgsGeometry::insertVertex( double x, double y, 01224 int beforeVertex, 01225 const GEOSCoordSequence* old_sequence, 01226 GEOSCoordSequence** new_sequence ) 01227 01228 { 01229 // Bounds checking 01230 if ( beforeVertex < 0 ) 01231 { 01232 *new_sequence = 0; 01233 return false; 01234 } 01235 01236 unsigned int numPoints; 01237 GEOSCoordSeq_getSize( old_sequence, &numPoints ); 01238 01239 *new_sequence = GEOSCoordSeq_create( numPoints + 1, 2 ); 01240 if ( !*new_sequence ) 01241 return false; 01242 01243 bool inserted = false; 01244 for ( unsigned int i = 0, j = 0; i < numPoints; i++, j++ ) 01245 { 01246 // Do we insert the new vertex here? 01247 if ( beforeVertex == static_cast<int>( i ) ) 01248 { 01249 GEOSCoordSeq_setX( *new_sequence, j, x ); 01250 GEOSCoordSeq_setY( *new_sequence, j, y ); 01251 j++; 01252 inserted = true; 01253 } 01254 01255 double aX, aY; 01256 GEOSCoordSeq_getX( old_sequence, i, &aX ); 01257 GEOSCoordSeq_getY( old_sequence, i, &aY ); 01258 01259 GEOSCoordSeq_setX( *new_sequence, j, aX ); 01260 GEOSCoordSeq_setY( *new_sequence, j, aY ); 01261 } 01262 01263 if ( !inserted ) 01264 { 01265 // The beforeVertex is greater than the actual number of vertices 01266 // in the geometry - append it. 01267 GEOSCoordSeq_setX( *new_sequence, numPoints, x ); 01268 GEOSCoordSeq_setY( *new_sequence, numPoints, y ); 01269 } 01270 // TODO: Check that the sequence is still simple, e.g. with GEOS_GEOM::Geometry->isSimple() 01271 01272 return inserted; 01273 } 01274 01275 bool QgsGeometry::moveVertex( double x, double y, int atVertex ) 01276 { 01277 int vertexnr = atVertex; 01278 01279 // TODO: implement with GEOS 01280 if ( mDirtyWkb ) 01281 { 01282 exportGeosToWkb(); 01283 } 01284 01285 if ( !mGeometry ) 01286 { 01287 QgsDebugMsg( "WKB geometry not available!" ); 01288 return false; 01289 } 01290 01291 QGis::WkbType wkbType; 01292 bool hasZValue = false; 01293 unsigned char* ptr = mGeometry + 1; 01294 memcpy( &wkbType, ptr, sizeof( wkbType ) ); 01295 ptr += sizeof( wkbType ); 01296 01297 switch ( wkbType ) 01298 { 01299 case QGis::WKBPoint25D: 01300 case QGis::WKBPoint: 01301 { 01302 if ( vertexnr == 0 ) 01303 { 01304 memcpy( ptr, &x, sizeof( double ) ); 01305 ptr += sizeof( double ); 01306 memcpy( ptr, &y, sizeof( double ) ); 01307 mDirtyGeos = true; 01308 return true; 01309 } 01310 else 01311 { 01312 return false; 01313 } 01314 } 01315 case QGis::WKBMultiPoint25D: 01316 hasZValue = true; 01317 case QGis::WKBMultiPoint: 01318 { 01319 int* nrPoints = ( int* )ptr; 01320 if ( vertexnr > *nrPoints || vertexnr < 0 ) 01321 { 01322 return false; 01323 } 01324 ptr += sizeof( int ); 01325 if ( hasZValue ) 01326 { 01327 ptr += ( 3 * sizeof( double ) + 1 + sizeof( int ) ) * vertexnr; 01328 } 01329 else 01330 { 01331 ptr += ( 2 * sizeof( double ) + 1 + sizeof( int ) ) * vertexnr; 01332 } 01333 ptr += ( 1 + sizeof( int ) ); 01334 memcpy( ptr, &x, sizeof( double ) ); 01335 ptr += sizeof( double ); 01336 memcpy( ptr, &y, sizeof( double ) ); 01337 mDirtyGeos = true; 01338 return true; 01339 } 01340 case QGis::WKBLineString25D: 01341 hasZValue = true; 01342 case QGis::WKBLineString: 01343 { 01344 int* nrPoints = ( int* )ptr; 01345 if ( vertexnr > *nrPoints || vertexnr < 0 ) 01346 { 01347 return false; 01348 } 01349 ptr += sizeof( int ); 01350 ptr += 2 * sizeof( double ) * vertexnr; 01351 if ( hasZValue ) 01352 { 01353 ptr += sizeof( double ) * vertexnr; 01354 } 01355 memcpy( ptr, &x, sizeof( double ) ); 01356 ptr += sizeof( double ); 01357 memcpy( ptr, &y, sizeof( double ) ); 01358 mDirtyGeos = true; 01359 return true; 01360 } 01361 case QGis::WKBMultiLineString25D: 01362 hasZValue = true; 01363 case QGis::WKBMultiLineString: 01364 { 01365 int* nrLines = ( int* )ptr; 01366 ptr += sizeof( int ); 01367 int* nrPoints = 0; //numer of points in a line 01368 int pointindex = 0; 01369 for ( int linenr = 0; linenr < *nrLines; ++linenr ) 01370 { 01371 ptr += sizeof( int ) + 1; 01372 nrPoints = ( int* )ptr; 01373 ptr += sizeof( int ); 01374 if ( vertexnr >= pointindex && vertexnr < pointindex + ( *nrPoints ) ) 01375 { 01376 ptr += ( vertexnr - pointindex ) * 2 * sizeof( double ); 01377 if ( hasZValue ) 01378 { 01379 ptr += ( vertexnr - pointindex ) * sizeof( double ); 01380 } 01381 memcpy( ptr, &x, sizeof( double ) ); 01382 memcpy( ptr + sizeof( double ), &y, sizeof( double ) ); 01383 mDirtyGeos = true; 01384 return true; 01385 } 01386 pointindex += ( *nrPoints ); 01387 ptr += 2 * sizeof( double ) * ( *nrPoints ); 01388 if ( hasZValue ) 01389 { 01390 ptr += sizeof( double ) * ( *nrPoints ); 01391 } 01392 } 01393 return false; 01394 } 01395 case QGis::WKBPolygon25D: 01396 hasZValue = true; 01397 case QGis::WKBPolygon: 01398 { 01399 int* nrRings = ( int* )ptr; 01400 ptr += sizeof( int ); 01401 int* nrPoints = 0; //numer of points in a ring 01402 int pointindex = 0; 01403 01404 for ( int ringnr = 0; ringnr < *nrRings; ++ringnr ) 01405 { 01406 nrPoints = ( int* )ptr; 01407 ptr += sizeof( int ); 01408 if ( vertexnr == pointindex || vertexnr == pointindex + ( *nrPoints - 1 ) )//move two points 01409 { 01410 memcpy( ptr, &x, sizeof( double ) ); 01411 memcpy( ptr + sizeof( double ), &y, sizeof( double ) ); 01412 if ( hasZValue ) 01413 { 01414 memcpy( ptr + 3*sizeof( double )*( *nrPoints - 1 ), &x, sizeof( double ) ); 01415 } 01416 else 01417 { 01418 memcpy( ptr + 2*sizeof( double )*( *nrPoints - 1 ), &x, sizeof( double ) ); 01419 } 01420 if ( hasZValue ) 01421 { 01422 memcpy( ptr + sizeof( double ) + 3*sizeof( double )*( *nrPoints - 1 ), &y, sizeof( double ) ); 01423 } 01424 else 01425 { 01426 memcpy( ptr + sizeof( double ) + 2*sizeof( double )*( *nrPoints - 1 ), &y, sizeof( double ) ); 01427 } 01428 mDirtyGeos = true; 01429 return true; 01430 } 01431 else if ( vertexnr > pointindex && vertexnr < pointindex + ( *nrPoints - 1 ) )//move only one point 01432 { 01433 ptr += 2 * sizeof( double ) * ( vertexnr - pointindex ); 01434 if ( hasZValue ) 01435 { 01436 ptr += sizeof( double ) * ( vertexnr - pointindex ); 01437 } 01438 memcpy( ptr, &x, sizeof( double ) ); 01439 ptr += sizeof( double ); 01440 memcpy( ptr, &y, sizeof( double ) ); 01441 mDirtyGeos = true; 01442 return true; 01443 } 01444 ptr += 2 * sizeof( double ) * ( *nrPoints ); 01445 if ( hasZValue ) 01446 { 01447 ptr += sizeof( double ) * ( *nrPoints ); 01448 } 01449 pointindex += *nrPoints; 01450 } 01451 return false; 01452 } 01453 case QGis::WKBMultiPolygon25D: 01454 hasZValue = true; 01455 case QGis::WKBMultiPolygon: 01456 { 01457 int* nrPolygons = ( int* )ptr; 01458 ptr += sizeof( int ); 01459 int* nrRings = 0; //number of rings in a polygon 01460 int* nrPoints = 0; //number of points in a ring 01461 int pointindex = 0; 01462 01463 for ( int polynr = 0; polynr < *nrPolygons; ++polynr ) 01464 { 01465 ptr += ( 1 + sizeof( int ) ); //skip endian and polygon type 01466 nrRings = ( int* )ptr; 01467 ptr += sizeof( int ); 01468 for ( int ringnr = 0; ringnr < *nrRings; ++ringnr ) 01469 { 01470 nrPoints = ( int* )ptr; 01471 ptr += sizeof( int ); 01472 if ( vertexnr == pointindex || vertexnr == pointindex + ( *nrPoints - 1 ) )//move two points 01473 { 01474 memcpy( ptr, &x, sizeof( double ) ); 01475 memcpy( ptr + sizeof( double ), &y, sizeof( double ) ); 01476 if ( hasZValue ) 01477 { 01478 memcpy( ptr + 3*sizeof( double )*( *nrPoints - 1 ), &x, sizeof( double ) ); 01479 } 01480 else 01481 { 01482 memcpy( ptr + 2*sizeof( double )*( *nrPoints - 1 ), &x, sizeof( double ) ); 01483 } 01484 if ( hasZValue ) 01485 { 01486 memcpy( ptr + sizeof( double ) + 3*sizeof( double )*( *nrPoints - 1 ), &y, sizeof( double ) ); 01487 } 01488 else 01489 { 01490 memcpy( ptr + sizeof( double ) + 2*sizeof( double )*( *nrPoints - 1 ), &y, sizeof( double ) ); 01491 } 01492 mDirtyGeos = true; 01493 return true; 01494 } 01495 else if ( vertexnr > pointindex && vertexnr < pointindex + ( *nrPoints - 1 ) )//move only one point 01496 { 01497 ptr += 2 * sizeof( double ) * ( vertexnr - pointindex ); 01498 if ( hasZValue ) 01499 { 01500 ptr += sizeof( double ) * ( vertexnr - pointindex ); 01501 } 01502 memcpy( ptr, &x, sizeof( double ) ); 01503 ptr += sizeof( double ); 01504 memcpy( ptr, &y, sizeof( double ) ); 01505 mDirtyGeos = true; 01506 return true; 01507 } 01508 ptr += 2 * sizeof( double ) * ( *nrPoints ); 01509 if ( hasZValue ) 01510 { 01511 ptr += sizeof( double ) * ( *nrPoints ); 01512 } 01513 pointindex += *nrPoints; 01514 } 01515 } 01516 return false; 01517 } 01518 01519 default: 01520 return false; 01521 } 01522 } 01523 01524 bool QgsGeometry::deleteVertex( int atVertex ) 01525 { 01526 int vertexnr = atVertex; 01527 bool success = false; 01528 01529 // TODO: implement with GEOS 01530 if ( mDirtyWkb ) 01531 { 01532 exportGeosToWkb(); 01533 } 01534 01535 if ( !mGeometry ) 01536 { 01537 QgsDebugMsg( "WKB geometry not available!" ); 01538 return false; 01539 } 01540 01541 //create a new geometry buffer for the modified geometry 01542 unsigned char* newbuffer; 01543 int pointindex = 0; 01544 QGis::WkbType wkbType; 01545 bool hasZValue = false; 01546 unsigned char* ptr = mGeometry + 1; 01547 memcpy( &wkbType, ptr, sizeof( wkbType ) ); 01548 01549 switch ( wkbType ) 01550 { 01551 case QGis::WKBPoint25D: 01552 case QGis::WKBLineString25D: 01553 case QGis::WKBPolygon25D: 01554 case QGis::WKBMultiPoint25D: 01555 case QGis::WKBMultiLineString25D: 01556 case QGis::WKBMultiPolygon25D: 01557 newbuffer = new unsigned char[mGeometrySize-3*sizeof( double )]; 01558 break; 01559 default: 01560 newbuffer = new unsigned char[mGeometrySize-2*sizeof( double )]; 01561 } 01562 01563 memcpy( newbuffer, mGeometry, 1 + sizeof( int ) ); //endian and type are the same 01564 01565 ptr += sizeof( wkbType ); 01566 unsigned char* newBufferPtr = newbuffer + 1 + sizeof( int ); 01567 01568 switch ( wkbType ) 01569 { 01570 case QGis::WKBPoint25D: 01571 case QGis::WKBPoint: 01572 { 01573 break; //cannot remove the only point vertex 01574 } 01575 case QGis::WKBMultiPoint25D: 01576 hasZValue = true; 01577 case QGis::WKBMultiPoint: 01578 { 01579 //todo 01580 break; 01581 } 01582 case QGis::WKBLineString25D: 01583 hasZValue = true; 01584 case QGis::WKBLineString: 01585 { 01586 int* nPoints = ( int* )ptr; 01587 if (( *nPoints ) < 3 || vertexnr > ( *nPoints ) - 1 || vertexnr < 0 ) //line needs at least 2 vertices 01588 { 01589 delete newbuffer; 01590 return false; 01591 } 01592 int newNPoints = ( *nPoints ) - 1; //new number of points 01593 memcpy( newBufferPtr, &newNPoints, sizeof( int ) ); 01594 ptr += sizeof( int ); 01595 newBufferPtr += sizeof( int ); 01596 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 01597 { 01598 if ( vertexnr != pointindex ) 01599 { 01600 memcpy( newBufferPtr, ptr, sizeof( double ) ); 01601 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) ); 01602 newBufferPtr += 2 * sizeof( double ); 01603 if ( hasZValue ) 01604 { 01605 newBufferPtr += sizeof( double ); 01606 } 01607 } 01608 else 01609 { 01610 success = true; 01611 } 01612 ptr += 2 * sizeof( double ); 01613 if ( hasZValue ) 01614 { 01615 ptr += sizeof( double ); 01616 } 01617 ++pointindex; 01618 } 01619 break; 01620 } 01621 case QGis::WKBMultiLineString25D: 01622 hasZValue = true; 01623 case QGis::WKBMultiLineString: 01624 { 01625 int* nLines = ( int* )ptr; 01626 memcpy( newBufferPtr, nLines, sizeof( int ) ); 01627 newBufferPtr += sizeof( int ); 01628 ptr += sizeof( int ); 01629 int* nPoints = 0; //number of points in a line 01630 int pointindex = 0; 01631 for ( int linenr = 0; linenr < *nLines; ++linenr ) 01632 { 01633 memcpy( newBufferPtr, ptr, sizeof( int ) + 1 ); 01634 ptr += ( sizeof( int ) + 1 ); 01635 newBufferPtr += ( sizeof( int ) + 1 ); 01636 nPoints = ( int* )ptr; 01637 ptr += sizeof( int ); 01638 int newNPoint; 01639 01640 //find out if the vertex is in this line 01641 if ( vertexnr >= pointindex && vertexnr < pointindex + ( *nPoints ) ) 01642 { 01643 if ( *nPoints < 3 ) //line needs at least 2 vertices 01644 { 01645 delete newbuffer; 01646 return false; 01647 } 01648 newNPoint = ( *nPoints ) - 1; 01649 } 01650 else 01651 { 01652 newNPoint = *nPoints; 01653 } 01654 memcpy( newBufferPtr, &newNPoint, sizeof( int ) ); 01655 newBufferPtr += sizeof( int ); 01656 01657 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 01658 { 01659 if ( vertexnr != pointindex ) 01660 { 01661 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 01662 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//y 01663 newBufferPtr += 2 * sizeof( double ); 01664 if ( hasZValue ) 01665 { 01666 newBufferPtr += sizeof( double ); 01667 } 01668 } 01669 else 01670 { 01671 success = true; 01672 } 01673 ptr += 2 * sizeof( double ); 01674 if ( hasZValue ) 01675 { 01676 ptr += sizeof( double ); 01677 } 01678 ++pointindex; 01679 } 01680 } 01681 break; 01682 } 01683 case QGis::WKBPolygon25D: 01684 hasZValue = true; 01685 case QGis::WKBPolygon: 01686 { 01687 int* nRings = ( int* )ptr; 01688 memcpy( newBufferPtr, nRings, sizeof( int ) ); 01689 ptr += sizeof( int ); 01690 newBufferPtr += sizeof( int ); 01691 int* nPoints = 0; //number of points in a ring 01692 int pointindex = 0; 01693 01694 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 01695 { 01696 nPoints = ( int* )ptr; 01697 ptr += sizeof( int ); 01698 int newNPoints; 01699 if ( vertexnr >= pointindex && vertexnr < pointindex + *nPoints )//vertex to delete is in this ring 01700 { 01701 if ( *nPoints < 5 ) //a ring has at least 3 points 01702 { 01703 delete newbuffer; 01704 return false; 01705 } 01706 newNPoints = *nPoints - 1; 01707 } 01708 else 01709 { 01710 newNPoints = *nPoints; 01711 } 01712 memcpy( newBufferPtr, &newNPoints, sizeof( int ) ); 01713 newBufferPtr += sizeof( int ); 01714 01715 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 01716 { 01717 if ( vertexnr != pointindex ) 01718 { 01719 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 01720 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//y 01721 newBufferPtr += 2 * sizeof( double ); 01722 if ( hasZValue ) 01723 { 01724 newBufferPtr += sizeof( double ); 01725 } 01726 } 01727 else 01728 { 01729 if ( pointnr == 0 )//adjust the last point of the ring 01730 { 01731 memcpy( ptr + ( *nPoints - 1 )*2*sizeof( double ), ptr + 2*sizeof( double ), sizeof( double ) ); 01732 memcpy( ptr + sizeof( double ) + ( *nPoints - 1 )*2*sizeof( double ), ptr + 3*sizeof( double ), sizeof( double ) ); 01733 } 01734 if ( pointnr == ( *nPoints ) - 1 ) 01735 { 01736 memcpy( newBufferPtr - ( *nPoints - 1 )*2*sizeof( double ), ptr - 2*sizeof( double ), sizeof( double ) ); 01737 memcpy( newBufferPtr - ( *nPoints - 1 )*2*sizeof( double ) + sizeof( double ), ptr - sizeof( double ), sizeof( double ) ); 01738 } 01739 success = true; 01740 } 01741 ptr += 2 * sizeof( double ); 01742 if ( hasZValue ) 01743 { 01744 ptr += sizeof( double ); 01745 } 01746 ++pointindex; 01747 } 01748 } 01749 break; 01750 } 01751 case QGis::WKBMultiPolygon25D: 01752 hasZValue = true; 01753 case QGis::WKBMultiPolygon: 01754 { 01755 int* nPolys = ( int* )ptr; 01756 memcpy( newBufferPtr, nPolys, sizeof( int ) ); 01757 newBufferPtr += sizeof( int ); 01758 ptr += sizeof( int ); 01759 int* nRings = 0; 01760 int* nPoints = 0; 01761 int pointindex = 0; 01762 01763 for ( int polynr = 0; polynr < *nPolys; ++polynr ) 01764 { 01765 memcpy( newBufferPtr, ptr, ( 1 + sizeof( int ) ) ); 01766 ptr += ( 1 + sizeof( int ) ); //skip endian and polygon type 01767 newBufferPtr += ( 1 + sizeof( int ) ); 01768 nRings = ( int* )ptr; 01769 memcpy( newBufferPtr, nRings, sizeof( int ) ); 01770 newBufferPtr += sizeof( int ); 01771 ptr += sizeof( int ); 01772 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 01773 { 01774 nPoints = ( int* )ptr; 01775 ptr += sizeof( int ); 01776 int newNPoints; 01777 if ( vertexnr >= pointindex && vertexnr < pointindex + *nPoints )//vertex to delete is in this ring 01778 { 01779 if ( *nPoints < 5 ) //a ring has at least 3 points 01780 { 01781 delete newbuffer; 01782 return false; 01783 } 01784 newNPoints = *nPoints - 1; 01785 } 01786 else 01787 { 01788 newNPoints = *nPoints; 01789 } 01790 memcpy( newBufferPtr, &newNPoints, sizeof( int ) ); 01791 newBufferPtr += sizeof( int ); 01792 01793 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 01794 { 01795 if ( vertexnr != pointindex ) 01796 { 01797 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 01798 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//y 01799 newBufferPtr += 2 * sizeof( double ); 01800 if ( hasZValue ) 01801 { 01802 newBufferPtr += sizeof( double ); 01803 } 01804 } 01805 else 01806 { 01807 if ( pointnr == 0 )//adjust the last point of the ring 01808 { 01809 memcpy( ptr + ( *nPoints - 1 )*2*sizeof( double ), ptr + 2*sizeof( double ), sizeof( double ) ); 01810 memcpy( ptr + sizeof( double ) + ( *nPoints - 1 )*2*sizeof( double ), ptr + 3*sizeof( double ), sizeof( double ) ); 01811 } 01812 if ( pointnr == ( *nPoints ) - 1 ) 01813 { 01814 memcpy( newBufferPtr - ( *nPoints - 1 )*2*sizeof( double ), ptr - 2*sizeof( double ), sizeof( double ) ); 01815 memcpy( newBufferPtr - ( *nPoints - 1 )*2*sizeof( double ) + sizeof( double ), ptr - sizeof( double ), sizeof( double ) ); 01816 } 01817 success = true; 01818 } 01819 ptr += 2 * sizeof( double ); 01820 if ( hasZValue ) 01821 { 01822 ptr += sizeof( double ); 01823 } 01824 ++pointindex; 01825 } 01826 } 01827 } 01828 break; 01829 } 01830 case QGis::WKBNoGeometry: 01831 case QGis::WKBUnknown: 01832 break; 01833 } 01834 if ( success ) 01835 { 01836 delete [] mGeometry; 01837 mGeometry = newbuffer; 01838 mGeometrySize -= ( 2 * sizeof( double ) ); 01839 if ( hasZValue ) 01840 { 01841 mGeometrySize -= sizeof( double ); 01842 } 01843 mDirtyGeos = true; 01844 return true; 01845 } 01846 else 01847 { 01848 delete[] newbuffer; 01849 return false; 01850 } 01851 } 01852 01853 bool QgsGeometry::insertVertex( double x, double y, int beforeVertex ) 01854 { 01855 int vertexnr = beforeVertex; 01856 bool success = false; 01857 01858 // TODO: implement with GEOS 01859 if ( mDirtyWkb ) 01860 { 01861 exportGeosToWkb(); 01862 } 01863 01864 if ( !mGeometry ) 01865 { 01866 QgsDebugMsg( "WKB geometry not available!" ); 01867 return false; 01868 } 01869 01870 //create a new geometry buffer for the modified geometry 01871 unsigned char* newbuffer; 01872 01873 int pointindex = 0; 01874 QGis::WkbType wkbType; 01875 bool hasZValue = false; 01876 01877 unsigned char* ptr = mGeometry + 1; 01878 memcpy( &wkbType, ptr, sizeof( wkbType ) ); 01879 01880 switch ( wkbType ) 01881 { 01882 case QGis::WKBPoint25D: 01883 case QGis::WKBLineString25D: 01884 case QGis::WKBPolygon25D: 01885 case QGis::WKBMultiPoint25D: 01886 case QGis::WKBMultiLineString25D: 01887 case QGis::WKBMultiPolygon25D: 01888 newbuffer = new unsigned char[mGeometrySize+3*sizeof( double )]; 01889 break; 01890 default: 01891 newbuffer = new unsigned char[mGeometrySize+2*sizeof( double )]; 01892 } 01893 memcpy( newbuffer, mGeometry, 1 + sizeof( int ) ); //endian and type are the same 01894 01895 ptr += sizeof( wkbType ); 01896 unsigned char* newBufferPtr = newbuffer + 1 + sizeof( int ); 01897 01898 switch ( wkbType ) 01899 { 01900 case QGis::WKBPoint25D: 01901 case QGis::WKBPoint://cannot insert a vertex before another one on point types 01902 { 01903 delete newbuffer; 01904 return false; 01905 } 01906 case QGis::WKBMultiPoint25D: 01907 hasZValue = true; 01908 case QGis::WKBMultiPoint: 01909 { 01910 //todo 01911 break; 01912 } 01913 case QGis::WKBLineString25D: 01914 hasZValue = true; 01915 case QGis::WKBLineString: 01916 { 01917 int* nPoints = ( int* )ptr; 01918 if ( vertexnr > *nPoints || vertexnr < 0 ) 01919 { 01920 break; 01921 } 01922 int newNPoints = ( *nPoints ) + 1; 01923 memcpy( newBufferPtr, &newNPoints, sizeof( int ) ); 01924 newBufferPtr += sizeof( int ); 01925 ptr += sizeof( int ); 01926 01927 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 01928 { 01929 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 01930 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//x 01931 ptr += 2 * sizeof( double ); 01932 if ( hasZValue ) 01933 { 01934 ptr += sizeof( double ); 01935 } 01936 newBufferPtr += 2 * sizeof( double ); 01937 if ( hasZValue ) 01938 { 01939 newBufferPtr += sizeof( double ); 01940 } 01941 ++pointindex; 01942 if ( pointindex == vertexnr ) 01943 { 01944 memcpy( newBufferPtr, &x, sizeof( double ) ); 01945 memcpy( newBufferPtr + sizeof( double ), &y, sizeof( double ) ); 01946 newBufferPtr += 2 * sizeof( double ); 01947 if ( hasZValue ) 01948 { 01949 newBufferPtr += sizeof( double ); 01950 } 01951 success = true; 01952 } 01953 } 01954 break; 01955 } 01956 case QGis::WKBMultiLineString25D: 01957 hasZValue = true; 01958 case QGis::WKBMultiLineString: 01959 { 01960 int* nLines = ( int* )ptr; 01961 int* nPoints = 0; //number of points in a line 01962 ptr += sizeof( int ); 01963 memcpy( newBufferPtr, nLines, sizeof( int ) ); 01964 newBufferPtr += sizeof( int ); 01965 int pointindex = 0; 01966 01967 for ( int linenr = 0; linenr < *nLines; ++linenr ) 01968 { 01969 memcpy( newBufferPtr, ptr, sizeof( int ) + 1 ); 01970 ptr += ( sizeof( int ) + 1 ); 01971 newBufferPtr += ( sizeof( int ) + 1 ); 01972 nPoints = ( int* )ptr; 01973 int newNPoints; 01974 if ( vertexnr >= pointindex && vertexnr < ( pointindex + ( *nPoints ) ) )//point is in this ring 01975 { 01976 newNPoints = ( *nPoints ) + 1; 01977 } 01978 else 01979 { 01980 newNPoints = *nPoints; 01981 } 01982 memcpy( newBufferPtr, &newNPoints, sizeof( double ) ); 01983 newBufferPtr += sizeof( int ); 01984 ptr += sizeof( int ); 01985 01986 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 01987 { 01988 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 01989 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//y 01990 ptr += 2 * sizeof( double ); 01991 newBufferPtr += 2 * sizeof( double ); 01992 if ( hasZValue ) 01993 { 01994 ptr += sizeof( double ); 01995 newBufferPtr += sizeof( double ); 01996 } 01997 ++pointindex; 01998 if ( pointindex == vertexnr ) 01999 { 02000 memcpy( newBufferPtr, &x, sizeof( double ) ); 02001 memcpy( newBufferPtr + sizeof( double ), &y, sizeof( double ) ); 02002 newBufferPtr += 2 * sizeof( double ); 02003 if ( hasZValue ) 02004 { 02005 newBufferPtr += sizeof( double ); 02006 } 02007 success = true; 02008 } 02009 } 02010 } 02011 break; 02012 } 02013 case QGis::WKBPolygon25D: 02014 hasZValue = true; 02015 case QGis::WKBPolygon: 02016 { 02017 int* nRings = ( int* )ptr; 02018 int* nPoints = 0; //number of points in a ring 02019 ptr += sizeof( int ); 02020 memcpy( newBufferPtr, nRings, sizeof( int ) ); 02021 newBufferPtr += sizeof( int ); 02022 int pointindex = 0; 02023 02024 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 02025 { 02026 nPoints = ( int* )ptr; 02027 int newNPoints; 02028 if ( vertexnr >= pointindex && vertexnr < ( pointindex + ( *nPoints ) ) )//point is in this ring 02029 { 02030 newNPoints = ( *nPoints ) + 1; 02031 } 02032 else 02033 { 02034 newNPoints = *nPoints; 02035 } 02036 memcpy( newBufferPtr, &newNPoints, sizeof( double ) ); 02037 newBufferPtr += sizeof( int ); 02038 ptr += sizeof( int ); 02039 02040 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02041 { 02042 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 02043 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//y 02044 ptr += 2 * sizeof( double ); 02045 newBufferPtr += 2 * sizeof( double ); 02046 if ( hasZValue ) 02047 { 02048 ptr += sizeof( double ); 02049 newBufferPtr += sizeof( double ); 02050 } 02051 ++pointindex; 02052 if ( pointindex == vertexnr ) 02053 { 02054 memcpy( newBufferPtr, &x, sizeof( double ) ); 02055 memcpy( newBufferPtr + sizeof( double ), &y, sizeof( double ) ); 02056 newBufferPtr += 2 * sizeof( double ); 02057 if ( hasZValue ) 02058 { 02059 newBufferPtr += sizeof( double ); 02060 } 02061 success = true; 02062 } 02063 } 02064 } 02065 break; 02066 } 02067 case QGis::WKBMultiPolygon25D: 02068 hasZValue = true; 02069 case QGis::WKBMultiPolygon: 02070 { 02071 int* nPolys = ( int* )ptr; 02072 int* nRings = 0; //number of rings in a polygon 02073 int* nPoints = 0; //number of points in a ring 02074 memcpy( newBufferPtr, nPolys, sizeof( int ) ); 02075 ptr += sizeof( int ); 02076 newBufferPtr += sizeof( int ); 02077 int pointindex = 0; 02078 02079 for ( int polynr = 0; polynr < *nPolys; ++polynr ) 02080 { 02081 memcpy( newBufferPtr, ptr, ( 1 + sizeof( int ) ) ); 02082 ptr += ( 1 + sizeof( int ) );//skip endian and polygon type 02083 newBufferPtr += ( 1 + sizeof( int ) ); 02084 nRings = ( int* )ptr; 02085 ptr += sizeof( int ); 02086 memcpy( newBufferPtr, nRings, sizeof( int ) ); 02087 newBufferPtr += sizeof( int ); 02088 02089 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 02090 { 02091 nPoints = ( int* )ptr; 02092 int newNPoints; 02093 if ( vertexnr >= pointindex && vertexnr < ( pointindex + ( *nPoints ) ) )//point is in this ring 02094 { 02095 newNPoints = ( *nPoints ) + 1; 02096 } 02097 else 02098 { 02099 newNPoints = *nPoints; 02100 } 02101 memcpy( newBufferPtr, &newNPoints, sizeof( double ) ); 02102 newBufferPtr += sizeof( int ); 02103 ptr += sizeof( int ); 02104 02105 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02106 { 02107 memcpy( newBufferPtr, ptr, sizeof( double ) );//x 02108 memcpy( newBufferPtr + sizeof( double ), ptr + sizeof( double ), sizeof( double ) );//y 02109 ptr += 2 * sizeof( double ); 02110 newBufferPtr += 2 * sizeof( double ); 02111 if ( hasZValue ) 02112 { 02113 ptr += sizeof( double ); 02114 newBufferPtr += sizeof( double ); 02115 } 02116 ++pointindex; 02117 if ( pointindex == vertexnr ) 02118 { 02119 memcpy( newBufferPtr, &x, sizeof( double ) ); 02120 memcpy( newBufferPtr + sizeof( double ), &y, sizeof( double ) ); 02121 newBufferPtr += 2 * sizeof( double ); 02122 if ( hasZValue ) 02123 { 02124 newBufferPtr += sizeof( double ); 02125 } 02126 success = true; 02127 } 02128 } 02129 } 02130 02131 } 02132 break; 02133 } 02134 case QGis::WKBNoGeometry: 02135 case QGis::WKBUnknown: 02136 break; 02137 } 02138 02139 if ( success ) 02140 { 02141 delete [] mGeometry; 02142 mGeometry = newbuffer; 02143 mGeometrySize += 2 * sizeof( double ); 02144 if ( hasZValue ) 02145 { 02146 mGeometrySize += sizeof( double ); 02147 } 02148 mDirtyGeos = true; 02149 return true; 02150 } 02151 else 02152 { 02153 delete newbuffer; 02154 return false; 02155 } 02156 } 02157 02158 QgsPoint QgsGeometry::vertexAt( int atVertex ) 02159 { 02160 double x, y; 02161 02162 if ( mDirtyWkb ) 02163 { 02164 exportGeosToWkb(); 02165 } 02166 02167 if ( !mGeometry ) 02168 { 02169 QgsDebugMsg( "WKB geometry not available!" ); 02170 return QgsPoint( 0, 0 ); 02171 } 02172 02173 QGis::WkbType wkbType; 02174 bool hasZValue = false; 02175 unsigned char* ptr; 02176 02177 memcpy( &wkbType, ( mGeometry + 1 ), sizeof( int ) ); 02178 switch ( wkbType ) 02179 { 02180 case QGis::WKBPoint25D: 02181 case QGis::WKBPoint: 02182 { 02183 if ( atVertex == 0 ) 02184 { 02185 ptr = mGeometry + 1 + sizeof( int ); 02186 memcpy( &x, ptr, sizeof( double ) ); 02187 ptr += sizeof( double ); 02188 memcpy( &y, ptr, sizeof( double ) ); 02189 return QgsPoint( x, y ); 02190 } 02191 else 02192 { 02193 return QgsPoint( 0, 0 ); 02194 } 02195 } 02196 case QGis::WKBLineString25D: 02197 hasZValue = true; 02198 case QGis::WKBLineString: 02199 { 02200 int *nPoints; 02201 // get number of points in the line 02202 ptr = mGeometry + 1 + sizeof( int ); // now at mGeometry.numPoints 02203 nPoints = ( int * ) ptr; 02204 02205 // return error if underflow 02206 if ( 0 > atVertex || *nPoints <= atVertex ) 02207 { 02208 return QgsPoint( 0, 0 ); 02209 } 02210 02211 // copy the vertex coordinates 02212 if ( hasZValue ) 02213 { 02214 ptr = mGeometry + 9 + ( atVertex * 3 * sizeof( double ) ); 02215 } 02216 else 02217 { 02218 ptr = mGeometry + 9 + ( atVertex * 2 * sizeof( double ) ); 02219 } 02220 memcpy( &x, ptr, sizeof( double ) ); 02221 ptr += sizeof( double ); 02222 memcpy( &y, ptr, sizeof( double ) ); 02223 return QgsPoint( x, y ); 02224 } 02225 case QGis::WKBPolygon25D: 02226 hasZValue = true; 02227 case QGis::WKBPolygon: 02228 { 02229 int *nRings; 02230 int *nPoints = 0; 02231 ptr = mGeometry + 1 + sizeof( int ); 02232 nRings = ( int* )ptr; 02233 ptr += sizeof( int ); 02234 int pointindex = 0; 02235 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 02236 { 02237 nPoints = ( int* )ptr; 02238 ptr += sizeof( int ); 02239 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02240 { 02241 if ( pointindex == atVertex ) 02242 { 02243 memcpy( &x, ptr, sizeof( double ) ); 02244 ptr += sizeof( double ); 02245 memcpy( &y, ptr, sizeof( double ) ); 02246 return QgsPoint( x, y ); 02247 } 02248 ptr += 2 * sizeof( double ); 02249 if ( hasZValue ) 02250 { 02251 ptr += sizeof( double ); 02252 } 02253 ++pointindex; 02254 } 02255 } 02256 return QgsPoint( 0, 0 ); 02257 } 02258 case QGis::WKBMultiPoint25D: 02259 hasZValue = true; 02260 case QGis::WKBMultiPoint: 02261 { 02262 ptr = mGeometry + 1 + sizeof( int ); 02263 int* nPoints = ( int* )ptr; 02264 if ( atVertex < 0 || atVertex >= *nPoints ) 02265 { 02266 return QgsPoint( 0, 0 ); 02267 } 02268 if ( hasZValue ) 02269 { 02270 ptr += atVertex * ( 3 * sizeof( double ) + 1 + sizeof( int ) ); 02271 } 02272 else 02273 { 02274 ptr += atVertex * ( 2 * sizeof( double ) + 1 + sizeof( int ) ); 02275 } 02276 ptr += 1 + sizeof( int ); 02277 memcpy( &x, ptr, sizeof( double ) ); 02278 ptr += sizeof( double ); 02279 memcpy( &y, ptr, sizeof( double ) ); 02280 return QgsPoint( x, y ); 02281 } 02282 case QGis::WKBMultiLineString25D: 02283 hasZValue = true; 02284 case QGis::WKBMultiLineString: 02285 { 02286 ptr = mGeometry + 1 + sizeof( int ); 02287 int* nLines = ( int* )ptr; 02288 int* nPoints = 0; //number of points in a line 02289 int pointindex = 0; //global point counter 02290 ptr += sizeof( int ); 02291 for ( int linenr = 0; linenr < *nLines; ++linenr ) 02292 { 02293 ptr += sizeof( int ) + 1; 02294 nPoints = ( int* )ptr; 02295 ptr += sizeof( int ); 02296 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02297 { 02298 if ( pointindex == atVertex ) 02299 { 02300 memcpy( &x, ptr, sizeof( double ) ); 02301 ptr += sizeof( double ); 02302 memcpy( &y, ptr, sizeof( double ) ); 02303 return QgsPoint( x, y ); 02304 } 02305 ptr += 2 * sizeof( double ); 02306 if ( hasZValue ) 02307 { 02308 ptr += sizeof( double ); 02309 } 02310 ++pointindex; 02311 } 02312 } 02313 return QgsPoint( 0, 0 ); 02314 } 02315 case QGis::WKBMultiPolygon25D: 02316 hasZValue = true; 02317 case QGis::WKBMultiPolygon: 02318 { 02319 ptr = mGeometry + 1 + sizeof( int ); 02320 int* nRings = 0;//number of rings in a polygon 02321 int* nPoints = 0;//number of points in a ring 02322 int pointindex = 0; //global point counter 02323 int* nPolygons = ( int* )ptr; 02324 ptr += sizeof( int ); 02325 for ( int polynr = 0; polynr < *nPolygons; ++polynr ) 02326 { 02327 ptr += ( 1 + sizeof( int ) ); //skip endian and polygon type 02328 nRings = ( int* )ptr; 02329 ptr += sizeof( int ); 02330 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 02331 { 02332 nPoints = ( int* )ptr; 02333 ptr += sizeof( int ); 02334 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02335 { 02336 if ( pointindex == atVertex ) 02337 { 02338 memcpy( &x, ptr, sizeof( double ) ); 02339 ptr += sizeof( double ); 02340 memcpy( &y, ptr, sizeof( double ) ); 02341 return QgsPoint( x, y ); 02342 } 02343 ++pointindex; 02344 ptr += 2 * sizeof( double ); 02345 if ( hasZValue ) 02346 { 02347 ptr += sizeof( double ); 02348 } 02349 } 02350 } 02351 } 02352 return QgsPoint( 0, 0 ); 02353 } 02354 default: 02355 QgsDebugMsg( "error: mGeometry type not recognized" ); 02356 return QgsPoint( 0, 0 ); 02357 } 02358 } 02359 02360 02361 double QgsGeometry::sqrDistToVertexAt( QgsPoint& point, int atVertex ) 02362 { 02363 QgsPoint pnt = vertexAt( atVertex ); 02364 if ( pnt != QgsPoint( 0, 0 ) ) 02365 { 02366 QgsDebugMsg( "Exiting with distance to " + pnt.toString() ); 02367 return point.sqrDist( pnt ); 02368 } 02369 else 02370 { 02371 QgsDebugMsg( "Exiting with std::numeric_limits<double>::max()." ); 02372 // probably safest to bail out with a very large number 02373 return std::numeric_limits<double>::max(); 02374 } 02375 } 02376 02377 02378 double QgsGeometry::closestVertexWithContext( const QgsPoint& point, int& atVertex ) 02379 { 02380 double sqrDist = std::numeric_limits<double>::max(); 02381 02382 try 02383 { 02384 // Initialise some stuff 02385 int closestVertexIndex = 0; 02386 02387 // set up the GEOS geometry 02388 if ( mDirtyGeos ) 02389 { 02390 exportWkbToGeos(); 02391 } 02392 02393 if ( !mGeos ) 02394 { 02395 return -1; 02396 } 02397 02398 const GEOSGeometry *g = GEOSGetExteriorRing( mGeos ); 02399 if ( !g ) 02400 return -1; 02401 02402 const GEOSCoordSequence *sequence = GEOSGeom_getCoordSeq( g ); 02403 02404 unsigned int n; 02405 GEOSCoordSeq_getSize( sequence, &n ); 02406 02407 for ( unsigned int i = 0; i < n; i++ ) 02408 { 02409 double x, y; 02410 GEOSCoordSeq_getX( sequence, i, &x ); 02411 GEOSCoordSeq_getY( sequence, i, &y ); 02412 02413 double testDist = point.sqrDist( x, y ); 02414 if ( testDist < sqrDist ) 02415 { 02416 closestVertexIndex = i; 02417 sqrDist = testDist; 02418 } 02419 } 02420 02421 atVertex = closestVertexIndex; 02422 } 02423 catch ( GEOSException &e ) 02424 { 02425 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 02426 return -1; 02427 } 02428 02429 return sqrDist; 02430 } 02431 02432 02433 double QgsGeometry::closestSegmentWithContext( 02434 const QgsPoint& point, 02435 QgsPoint& minDistPoint, 02436 int& afterVertex, 02437 double* leftOf, 02438 double epsilon ) 02439 { 02440 QgsDebugMsg( "Entering." ); 02441 QgsPoint distPoint; 02442 02443 QGis::WkbType wkbType; 02444 bool hasZValue = false; 02445 double *thisx = NULL; 02446 double *thisy = NULL; 02447 double *prevx = NULL; 02448 double *prevy = NULL; 02449 double testdist; 02450 int closestSegmentIndex = 0; 02451 02452 // Initialise some stuff 02453 double sqrDist = std::numeric_limits<double>::max(); 02454 02455 // TODO: implement with GEOS 02456 if ( mDirtyWkb ) //convert latest geos to mGeometry 02457 { 02458 exportGeosToWkb(); 02459 } 02460 02461 if ( !mGeometry ) 02462 { 02463 QgsDebugMsg( "WKB geometry not available!" ); 02464 return -1; 02465 } 02466 02467 memcpy( &wkbType, ( mGeometry + 1 ), sizeof( int ) ); 02468 02469 switch ( wkbType ) 02470 { 02471 case QGis::WKBPoint25D: 02472 case QGis::WKBPoint: 02473 case QGis::WKBMultiPoint25D: 02474 case QGis::WKBMultiPoint: 02475 { 02476 // Points have no lines 02477 return -1; 02478 } 02479 case QGis::WKBLineString25D: 02480 hasZValue = true; 02481 case QGis::WKBLineString: 02482 { 02483 unsigned char* ptr = mGeometry + 1 + sizeof( int ); 02484 int* npoints = ( int* ) ptr; 02485 ptr += sizeof( int ); 02486 for ( int index = 0; index < *npoints; ++index ) 02487 { 02488 if ( index > 0 ) 02489 { 02490 prevx = thisx; 02491 prevy = thisy; 02492 } 02493 thisx = ( double* ) ptr; 02494 ptr += sizeof( double ); 02495 thisy = ( double* ) ptr; 02496 02497 if ( index > 0 ) 02498 { 02499 if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist ) 02500 { 02501 closestSegmentIndex = index; 02502 sqrDist = testdist; 02503 minDistPoint = distPoint; 02504 if ( leftOf ) 02505 { 02506 *leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy ); 02507 } 02508 } 02509 } 02510 ptr += sizeof( double ); 02511 if ( hasZValue ) 02512 { 02513 ptr += sizeof( double ); 02514 } 02515 } 02516 afterVertex = closestSegmentIndex; 02517 break; 02518 } 02519 case QGis::WKBMultiLineString25D: 02520 hasZValue = true; 02521 case QGis::WKBMultiLineString: 02522 { 02523 unsigned char* ptr = mGeometry + 1 + sizeof( int ); 02524 int* nLines = ( int* )ptr; 02525 ptr += sizeof( int ); 02526 int* nPoints = 0; //number of points in a line 02527 int pointindex = 0;//global pointindex 02528 for ( int linenr = 0; linenr < *nLines; ++linenr ) 02529 { 02530 ptr += sizeof( int ) + 1; 02531 nPoints = ( int* )ptr; 02532 ptr += sizeof( int ); 02533 prevx = 0; 02534 prevy = 0; 02535 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02536 { 02537 thisx = ( double* ) ptr; 02538 ptr += sizeof( double ); 02539 thisy = ( double* ) ptr; 02540 ptr += sizeof( double ); 02541 if ( hasZValue ) 02542 { 02543 ptr += sizeof( double ); 02544 } 02545 if ( prevx && prevy ) 02546 { 02547 if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist ) 02548 { 02549 closestSegmentIndex = pointindex; 02550 sqrDist = testdist; 02551 minDistPoint = distPoint; 02552 if ( leftOf ) 02553 { 02554 *leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy ); 02555 } 02556 } 02557 } 02558 prevx = thisx; 02559 prevy = thisy; 02560 ++pointindex; 02561 } 02562 } 02563 afterVertex = closestSegmentIndex; 02564 break; 02565 } 02566 case QGis::WKBPolygon25D: 02567 hasZValue = true; 02568 case QGis::WKBPolygon: 02569 { 02570 int index = 0; 02571 unsigned char* ptr = mGeometry + 1 + sizeof( int ); 02572 int* nrings = ( int* )ptr; 02573 int* npoints = 0; //number of points in a ring 02574 ptr += sizeof( int ); 02575 for ( int ringnr = 0; ringnr < *nrings; ++ringnr )//loop over rings 02576 { 02577 npoints = ( int* )ptr; 02578 ptr += sizeof( int ); 02579 prevx = 0; 02580 prevy = 0; 02581 for ( int pointnr = 0; pointnr < *npoints; ++pointnr )//loop over points in a ring 02582 { 02583 thisx = ( double* )ptr; 02584 ptr += sizeof( double ); 02585 thisy = ( double* )ptr; 02586 ptr += sizeof( double ); 02587 if ( hasZValue ) 02588 { 02589 ptr += sizeof( double ); 02590 } 02591 if ( prevx && prevy ) 02592 { 02593 if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist ) 02594 { 02595 closestSegmentIndex = index; 02596 sqrDist = testdist; 02597 minDistPoint = distPoint; 02598 if ( leftOf ) 02599 { 02600 *leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy ); 02601 } 02602 } 02603 } 02604 prevx = thisx; 02605 prevy = thisy; 02606 ++index; 02607 } 02608 } 02609 afterVertex = closestSegmentIndex; 02610 break; 02611 } 02612 case QGis::WKBMultiPolygon25D: 02613 hasZValue = true; 02614 case QGis::WKBMultiPolygon: 02615 { 02616 unsigned char* ptr = mGeometry + 1 + sizeof( int ); 02617 int* nRings = 0; 02618 int* nPoints = 0; 02619 int pointindex = 0; 02620 int* nPolygons = ( int* )ptr; 02621 ptr += sizeof( int ); 02622 for ( int polynr = 0; polynr < *nPolygons; ++polynr ) 02623 { 02624 ptr += ( 1 + sizeof( int ) ); 02625 nRings = ( int* )ptr; 02626 ptr += sizeof( int ); 02627 for ( int ringnr = 0; ringnr < *nRings; ++ringnr ) 02628 { 02629 nPoints = ( int* )ptr; 02630 ptr += sizeof( int ); 02631 prevx = 0; 02632 prevy = 0; 02633 for ( int pointnr = 0; pointnr < *nPoints; ++pointnr ) 02634 { 02635 thisx = ( double* )ptr; 02636 ptr += sizeof( double ); 02637 thisy = ( double* )ptr; 02638 ptr += sizeof( double ); 02639 if ( hasZValue ) 02640 { 02641 ptr += sizeof( double ); 02642 } 02643 if ( prevx && prevy ) 02644 { 02645 if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist ) 02646 { 02647 closestSegmentIndex = pointindex; 02648 sqrDist = testdist; 02649 minDistPoint = distPoint; 02650 if ( leftOf ) 02651 { 02652 *leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy ); 02653 } 02654 } 02655 } 02656 prevx = thisx; 02657 prevy = thisy; 02658 ++pointindex; 02659 } 02660 } 02661 } 02662 afterVertex = closestSegmentIndex; 02663 break; 02664 } 02665 case QGis::WKBUnknown: 02666 default: 02667 return -1; 02668 break; 02669 } // switch (wkbType) 02670 02671 02672 QgsDebugMsg( QString( "Exiting with nearest point %1, dist %2." ) 02673 .arg( point.toString() ).arg( sqrDist ) ); 02674 02675 return sqrDist; 02676 } 02677 02678 int QgsGeometry::addRing( const QList<QgsPoint>& ring ) 02679 { 02680 //bail out if this geometry is not polygon/multipolygon 02681 if ( type() != QGis::Polygon ) 02682 return 1; 02683 02684 //test for invalid geometries 02685 if ( ring.size() < 4 ) 02686 return 3; 02687 02688 //ring must be closed 02689 if ( ring.first() != ring.last() ) 02690 return 2; 02691 02692 //create geos geometry from wkb if not already there 02693 if ( mDirtyGeos ) 02694 { 02695 exportWkbToGeos(); 02696 } 02697 02698 if ( !mGeos ) 02699 { 02700 return 6; 02701 } 02702 02703 int type = GEOSGeomTypeId( mGeos ); 02704 02705 //Fill GEOS Polygons of the feature into list 02706 QVector<const GEOSGeometry*> polygonList; 02707 02708 if ( wkbType() == QGis::WKBPolygon ) 02709 { 02710 if ( type != GEOS_POLYGON ) 02711 return 1; 02712 02713 polygonList << mGeos; 02714 } 02715 else if ( wkbType() == QGis::WKBMultiPolygon ) 02716 { 02717 if ( type != GEOS_MULTIPOLYGON ) 02718 return 1; 02719 02720 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); ++i ) 02721 polygonList << GEOSGetGeometryN( mGeos, i ); 02722 } 02723 02724 //create new ring 02725 GEOSGeometry *newRing = 0; 02726 GEOSGeometry *newRingPolygon = 0; 02727 02728 try 02729 { 02730 newRing = createGeosLinearRing( ring.toVector() ); 02731 if ( !GEOSisValid( newRing ) ) 02732 { 02733 throwGEOSException( "ring is invalid" ); 02734 } 02735 02736 newRingPolygon = createGeosPolygon( newRing ); 02737 if ( !GEOSisValid( newRingPolygon ) ) 02738 { 02739 throwGEOSException( "ring is invalid" ); 02740 } 02741 } 02742 catch ( GEOSException &e ) 02743 { 02744 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 02745 02746 if ( newRingPolygon ) 02747 GEOSGeom_destroy( newRingPolygon ); 02748 else if ( newRing ) 02749 GEOSGeom_destroy( newRing ); 02750 02751 return 3; 02752 } 02753 02754 QVector<GEOSGeometry*> rings; 02755 02756 int i; 02757 for ( i = 0; i < polygonList.size(); i++ ) 02758 { 02759 for ( int j = 0; j < rings.size(); j++ ) 02760 GEOSGeom_destroy( rings[j] ); 02761 rings.clear(); 02762 02763 GEOSGeometry *shellRing = 0; 02764 GEOSGeometry *shell = 0; 02765 try 02766 { 02767 shellRing = GEOSGeom_clone( GEOSGetExteriorRing( polygonList[i] ) ); 02768 shell = createGeosPolygon( shellRing ); 02769 02770 if ( !GEOSWithin( newRingPolygon, shell ) ) 02771 { 02772 GEOSGeom_destroy( shell ); 02773 continue; 02774 } 02775 } 02776 catch ( GEOSException &e ) 02777 { 02778 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 02779 02780 if ( shell ) 02781 GEOSGeom_destroy( shell ); 02782 else if ( shellRing ) 02783 GEOSGeom_destroy( shellRing ); 02784 02785 GEOSGeom_destroy( newRingPolygon ); 02786 02787 return 4; 02788 } 02789 02790 // add outer ring 02791 rings << GEOSGeom_clone( shellRing ); 02792 02793 GEOSGeom_destroy( shell ); 02794 02795 // check inner rings 02796 int n = GEOSGetNumInteriorRings( polygonList[i] ); 02797 02798 int j; 02799 for ( j = 0; j < n; j++ ) 02800 { 02801 GEOSGeometry *holeRing = 0; 02802 GEOSGeometry *hole = 0; 02803 try 02804 { 02805 holeRing = GEOSGeom_clone( GEOSGetInteriorRingN( polygonList[i], j ) ); 02806 hole = createGeosPolygon( holeRing ); 02807 02808 if ( !GEOSDisjoint( hole, newRingPolygon ) ) 02809 { 02810 GEOSGeom_destroy( hole ); 02811 break; 02812 } 02813 } 02814 catch ( GEOSException &e ) 02815 { 02816 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 02817 02818 if ( hole ) 02819 GEOSGeom_destroy( hole ); 02820 else if ( holeRing ) 02821 GEOSGeom_destroy( holeRing ); 02822 02823 break; 02824 } 02825 02826 rings << GEOSGeom_clone( holeRing ); 02827 GEOSGeom_destroy( hole ); 02828 } 02829 02830 if ( j == n ) 02831 // this is it... 02832 break; 02833 } 02834 02835 if ( i == polygonList.size() ) 02836 { 02837 // clear rings 02838 for ( int j = 0; j < rings.size(); j++ ) 02839 GEOSGeom_destroy( rings[j] ); 02840 rings.clear(); 02841 02842 GEOSGeom_destroy( newRingPolygon ); 02843 02844 // no containing polygon found 02845 return 5; 02846 } 02847 02848 rings << GEOSGeom_clone( newRing ); 02849 GEOSGeom_destroy( newRingPolygon ); 02850 02851 GEOSGeometry *newPolygon = createGeosPolygon( rings ); 02852 02853 if ( wkbType() == QGis::WKBPolygon ) 02854 { 02855 GEOSGeom_destroy( mGeos ); 02856 mGeos = newPolygon; 02857 } 02858 else if ( wkbType() == QGis::WKBMultiPolygon ) 02859 { 02860 QVector<GEOSGeometry*> newPolygons; 02861 02862 for ( int j = 0; j < polygonList.size(); j++ ) 02863 { 02864 newPolygons << ( i == j ? newPolygon : GEOSGeom_clone( polygonList[j] ) ); 02865 } 02866 02867 GEOSGeom_destroy( mGeos ); 02868 mGeos = createGeosCollection( GEOS_MULTIPOLYGON, newPolygons ); 02869 } 02870 02871 mDirtyWkb = true; 02872 mDirtyGeos = false; 02873 return 0; 02874 } 02875 02876 int QgsGeometry::addPart( const QList<QgsPoint> &points ) 02877 { 02878 QGis::GeometryType geomType = type(); 02879 02880 switch ( geomType ) 02881 { 02882 case QGis::Point: 02883 // only one part at a time 02884 if ( points.size() != 1 ) 02885 { 02886 QgsDebugMsg( "expected 1 point: " + QString::number( points.size() ) ); 02887 return 2; 02888 } 02889 break; 02890 02891 case QGis::Line: 02892 // Line needs to have at least two points and must be closed 02893 if ( points.size() < 3 ) 02894 { 02895 QgsDebugMsg( "line must at least have two points: " + QString::number( points.size() ) ); 02896 return 2; 02897 } 02898 break; 02899 02900 case QGis::Polygon: 02901 // Ring needs to have at least three points and must be closed 02902 if ( points.size() < 4 ) 02903 { 02904 QgsDebugMsg( "polygon must at least have three points: " + QString::number( points.size() ) ); 02905 return 2; 02906 } 02907 02908 // ring must be closed 02909 if ( points.first() != points.last() ) 02910 { 02911 QgsDebugMsg( "polygon not closed" ); 02912 return 2; 02913 } 02914 break; 02915 02916 default: 02917 QgsDebugMsg( "unsupported geometry type: " + QString::number( geomType ) ); 02918 return 2; 02919 } 02920 02921 if ( !isMultipart() && !convertToMultiType() ) 02922 { 02923 QgsDebugMsg( "could not convert to multipart" ); 02924 return 1; 02925 } 02926 02927 //create geos geometry from wkb if not already there 02928 if ( mDirtyGeos ) 02929 { 02930 exportWkbToGeos(); 02931 } 02932 02933 if ( !mGeos ) 02934 { 02935 QgsDebugMsg( "GEOS geometry not available!" ); 02936 return 4; 02937 } 02938 02939 int geosType = GEOSGeomTypeId( mGeos ); 02940 GEOSGeometry *newPart = 0; 02941 02942 switch ( geomType ) 02943 { 02944 case QGis::Point: 02945 newPart = createGeosPoint( points[0] ); 02946 break; 02947 02948 case QGis::Line: 02949 newPart = createGeosLineString( points.toVector() ); 02950 break; 02951 02952 case QGis::Polygon: 02953 { 02954 //create new polygon from ring 02955 GEOSGeometry *newRing = 0; 02956 02957 try 02958 { 02959 newRing = createGeosLinearRing( points.toVector() ); 02960 if ( !GEOSisValid( newRing ) ) 02961 throw GEOSException( "ring invalid" ); 02962 02963 newPart = createGeosPolygon( newRing ); 02964 } 02965 catch ( GEOSException &e ) 02966 { 02967 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 02968 02969 if ( newRing ) 02970 GEOSGeom_destroy( newRing ); 02971 02972 return 2; 02973 } 02974 } 02975 break; 02976 02977 default: 02978 QgsDebugMsg( "unsupported type: " + QString::number( type() ) ); 02979 return 2; 02980 } 02981 02982 Q_ASSERT( newPart ); 02983 02984 try 02985 { 02986 if ( !GEOSisValid( newPart ) ) 02987 throw GEOSException( "new part geometry invalid" ); 02988 } 02989 catch ( GEOSException &e ) 02990 { 02991 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 02992 02993 if ( newPart ) 02994 GEOSGeom_destroy( newPart ); 02995 02996 QgsDebugMsg( "part invalid: " + e.what() ); 02997 return 2; 02998 } 02999 03000 QVector<GEOSGeometry*> parts; 03001 03002 //create new multipolygon 03003 int n = GEOSGetNumGeometries( mGeos ); 03004 int i; 03005 for ( i = 0; i < n; ++i ) 03006 { 03007 const GEOSGeometry *partN = GEOSGetGeometryN( mGeos, i ); 03008 03009 if ( geomType == QGis::Polygon && !GEOSDisjoint( partN, newPart ) ) 03010 //bail out if new polygon is not disjoint with existing ones 03011 break; 03012 03013 parts << GEOSGeom_clone( partN ); 03014 } 03015 03016 if ( i < n ) 03017 { 03018 // bailed out 03019 for ( int i = 0; i < parts.size(); i++ ) 03020 GEOSGeom_destroy( parts[i] ); 03021 03022 QgsDebugMsg( "new polygon part not disjoint" ); 03023 return 3; 03024 } 03025 03026 parts << newPart; 03027 03028 GEOSGeom_destroy( mGeos ); 03029 03030 mGeos = createGeosCollection( geosType, parts ); 03031 03032 mDirtyWkb = true; 03033 mDirtyGeos = false; 03034 03035 return 0; 03036 } 03037 03038 int QgsGeometry::translate( double dx, double dy ) 03039 { 03040 if ( mDirtyWkb ) 03041 { 03042 exportGeosToWkb(); 03043 } 03044 03045 if ( !mGeometry ) 03046 { 03047 QgsDebugMsg( "WKB geometry not available!" ); 03048 return 1; 03049 } 03050 03051 QGis::WkbType wkbType; 03052 memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); 03053 bool hasZValue = false; 03054 int wkbPosition = 5; 03055 03056 switch ( wkbType ) 03057 { 03058 case QGis::WKBPoint25D: 03059 case QGis::WKBPoint: 03060 { 03061 translateVertex( wkbPosition, dx, dy, hasZValue ); 03062 } 03063 break; 03064 03065 case QGis::WKBLineString25D: 03066 hasZValue = true; 03067 case QGis::WKBLineString: 03068 { 03069 int* npoints = ( int* )( &mGeometry[wkbPosition] ); 03070 wkbPosition += sizeof( int ); 03071 for ( int index = 0; index < *npoints; ++index ) 03072 { 03073 translateVertex( wkbPosition, dx, dy, hasZValue ); 03074 } 03075 break; 03076 } 03077 03078 case QGis::WKBPolygon25D: 03079 hasZValue = true; 03080 case QGis::WKBPolygon: 03081 { 03082 int* nrings = ( int* )( &( mGeometry[wkbPosition] ) ); 03083 wkbPosition += sizeof( int ); 03084 int* npoints; 03085 03086 for ( int index = 0; index < *nrings; ++index ) 03087 { 03088 npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03089 wkbPosition += sizeof( int ); 03090 for ( int index2 = 0; index2 < *npoints; ++index2 ) 03091 { 03092 translateVertex( wkbPosition, dx, dy, hasZValue ); 03093 } 03094 } 03095 break; 03096 } 03097 03098 case QGis::WKBMultiPoint25D: 03099 hasZValue = true; 03100 case QGis::WKBMultiPoint: 03101 { 03102 int* npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03103 wkbPosition += sizeof( int ); 03104 for ( int index = 0; index < *npoints; ++index ) 03105 { 03106 wkbPosition += ( sizeof( int ) + 1 ); 03107 translateVertex( wkbPosition, dx, dy, hasZValue ); 03108 } 03109 break; 03110 } 03111 03112 case QGis::WKBMultiLineString25D: 03113 hasZValue = true; 03114 case QGis::WKBMultiLineString: 03115 { 03116 int* nlines = ( int* )( &( mGeometry[wkbPosition] ) ); 03117 int* npoints = 0; 03118 wkbPosition += sizeof( int ); 03119 for ( int index = 0; index < *nlines; ++index ) 03120 { 03121 wkbPosition += ( sizeof( int ) + 1 ); 03122 npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03123 wkbPosition += sizeof( int ); 03124 for ( int index2 = 0; index2 < *npoints; ++index2 ) 03125 { 03126 translateVertex( wkbPosition, dx, dy, hasZValue ); 03127 } 03128 } 03129 break; 03130 } 03131 03132 case QGis::WKBMultiPolygon25D: 03133 hasZValue = true; 03134 case QGis::WKBMultiPolygon: 03135 { 03136 int* npolys = ( int* )( &( mGeometry[wkbPosition] ) ); 03137 int* nrings; 03138 int* npoints; 03139 wkbPosition += sizeof( int ); 03140 for ( int index = 0; index < *npolys; ++index ) 03141 { 03142 wkbPosition += ( 1 + sizeof( int ) ); //skip endian and polygon type 03143 nrings = ( int* )( &( mGeometry[wkbPosition] ) ); 03144 wkbPosition += sizeof( int ); 03145 for ( int index2 = 0; index2 < *nrings; ++index2 ) 03146 { 03147 npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03148 wkbPosition += sizeof( int ); 03149 for ( int index3 = 0; index3 < *npoints; ++index3 ) 03150 { 03151 translateVertex( wkbPosition, dx, dy, hasZValue ); 03152 } 03153 } 03154 } 03155 } 03156 03157 default: 03158 break; 03159 } 03160 mDirtyGeos = true; 03161 return 0; 03162 } 03163 03164 int QgsGeometry::transform( const QgsCoordinateTransform& ct ) 03165 { 03166 if ( mDirtyWkb ) 03167 { 03168 exportGeosToWkb(); 03169 } 03170 03171 if ( !mGeometry ) 03172 { 03173 QgsDebugMsg( "WKB geometry not available!" ); 03174 return 1; 03175 } 03176 03177 QGis::WkbType wkbType; 03178 memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); 03179 bool hasZValue = false; 03180 int wkbPosition = 5; 03181 03182 switch ( wkbType ) 03183 { 03184 case QGis::WKBPoint25D: 03185 case QGis::WKBPoint: 03186 { 03187 transformVertex( wkbPosition, ct, hasZValue ); 03188 } 03189 break; 03190 03191 case QGis::WKBLineString25D: 03192 hasZValue = true; 03193 case QGis::WKBLineString: 03194 { 03195 int* npoints = ( int* )( &mGeometry[wkbPosition] ); 03196 wkbPosition += sizeof( int ); 03197 for ( int index = 0; index < *npoints; ++index ) 03198 { 03199 transformVertex( wkbPosition, ct, hasZValue ); 03200 } 03201 break; 03202 } 03203 03204 case QGis::WKBPolygon25D: 03205 hasZValue = true; 03206 case QGis::WKBPolygon: 03207 { 03208 int* nrings = ( int* )( &( mGeometry[wkbPosition] ) ); 03209 wkbPosition += sizeof( int ); 03210 int* npoints; 03211 03212 for ( int index = 0; index < *nrings; ++index ) 03213 { 03214 npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03215 wkbPosition += sizeof( int ); 03216 for ( int index2 = 0; index2 < *npoints; ++index2 ) 03217 { 03218 transformVertex( wkbPosition, ct, hasZValue ); 03219 } 03220 } 03221 break; 03222 } 03223 03224 case QGis::WKBMultiPoint25D: 03225 hasZValue = true; 03226 case QGis::WKBMultiPoint: 03227 { 03228 int* npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03229 wkbPosition += sizeof( int ); 03230 for ( int index = 0; index < *npoints; ++index ) 03231 { 03232 wkbPosition += ( sizeof( int ) + 1 ); 03233 transformVertex( wkbPosition, ct, hasZValue ); 03234 } 03235 break; 03236 } 03237 03238 case QGis::WKBMultiLineString25D: 03239 hasZValue = true; 03240 case QGis::WKBMultiLineString: 03241 { 03242 int* nlines = ( int* )( &( mGeometry[wkbPosition] ) ); 03243 int* npoints = 0; 03244 wkbPosition += sizeof( int ); 03245 for ( int index = 0; index < *nlines; ++index ) 03246 { 03247 wkbPosition += ( sizeof( int ) + 1 ); 03248 npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03249 wkbPosition += sizeof( int ); 03250 for ( int index2 = 0; index2 < *npoints; ++index2 ) 03251 { 03252 transformVertex( wkbPosition, ct, hasZValue ); 03253 } 03254 } 03255 break; 03256 } 03257 03258 case QGis::WKBMultiPolygon25D: 03259 hasZValue = true; 03260 case QGis::WKBMultiPolygon: 03261 { 03262 int* npolys = ( int* )( &( mGeometry[wkbPosition] ) ); 03263 int* nrings; 03264 int* npoints; 03265 wkbPosition += sizeof( int ); 03266 for ( int index = 0; index < *npolys; ++index ) 03267 { 03268 wkbPosition += ( 1 + sizeof( int ) ); //skip endian and polygon type 03269 nrings = ( int* )( &( mGeometry[wkbPosition] ) ); 03270 wkbPosition += sizeof( int ); 03271 for ( int index2 = 0; index2 < *nrings; ++index2 ) 03272 { 03273 npoints = ( int* )( &( mGeometry[wkbPosition] ) ); 03274 wkbPosition += sizeof( int ); 03275 for ( int index3 = 0; index3 < *npoints; ++index3 ) 03276 { 03277 transformVertex( wkbPosition, ct, hasZValue ); 03278 } 03279 } 03280 } 03281 } 03282 03283 default: 03284 break; 03285 } 03286 mDirtyGeos = true; 03287 return 0; 03288 } 03289 03290 int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries, bool topological, QList<QgsPoint> &topologyTestPoints ) 03291 { 03292 int returnCode = 0; 03293 03294 //return if this type is point/multipoint 03295 if ( type() == QGis::Point ) 03296 { 03297 return 1; //cannot split points 03298 } 03299 03300 //make sure, mGeos and mWkb are there and up-to-date 03301 if ( mDirtyWkb ) 03302 { 03303 exportGeosToWkb(); 03304 } 03305 03306 if ( mDirtyGeos ) 03307 { 03308 exportWkbToGeos(); 03309 } 03310 03311 if ( !mGeos ) 03312 { 03313 return 1; 03314 } 03315 03316 if ( !GEOSisValid( mGeos ) ) 03317 { 03318 return 7; 03319 } 03320 03321 //make sure splitLine is valid 03322 if ( splitLine.size() < 2 ) 03323 { 03324 return 1; 03325 } 03326 03327 newGeometries.clear(); 03328 03329 try 03330 { 03331 GEOSGeometry *splitLineGeos = createGeosLineString( splitLine.toVector() ); 03332 if ( !GEOSisValid( splitLineGeos ) || !GEOSisSimple( splitLineGeos ) ) 03333 { 03334 GEOSGeom_destroy( splitLineGeos ); 03335 return 1; 03336 } 03337 03338 if ( topological ) 03339 { 03340 //find out candidate points for topological corrections 03341 if ( topologicalTestPointsSplit( splitLineGeos, topologyTestPoints ) != 0 ) 03342 { 03343 return 1; 03344 } 03345 } 03346 03347 //call split function depending on geometry type 03348 if ( type() == QGis::Line ) 03349 { 03350 returnCode = splitLinearGeometry( splitLineGeos, newGeometries ); 03351 GEOSGeom_destroy( splitLineGeos ); 03352 } 03353 else if ( type() == QGis::Polygon ) 03354 { 03355 returnCode = splitPolygonGeometry( splitLineGeos, newGeometries ); 03356 GEOSGeom_destroy( splitLineGeos ); 03357 } 03358 else 03359 { 03360 return 1; 03361 } 03362 } 03363 CATCH_GEOS( 2 ) 03364 03365 return returnCode; 03366 } 03367 03369 int QgsGeometry::reshapeGeometry( const QList<QgsPoint>& reshapeWithLine ) 03370 { 03371 if ( reshapeWithLine.size() < 2 ) 03372 { 03373 return 1; 03374 } 03375 03376 if ( type() == QGis::Point ) 03377 { 03378 return 1; //cannot reshape points 03379 } 03380 03381 GEOSGeometry* reshapeLineGeos = createGeosLineString( reshapeWithLine.toVector() ); 03382 03383 //make sure this geos geometry is up-to-date 03384 if ( mDirtyGeos ) 03385 { 03386 exportWkbToGeos(); 03387 } 03388 03389 if ( !mGeos ) 03390 { 03391 return 1; 03392 } 03393 03394 //single or multi? 03395 int numGeoms = GEOSGetNumGeometries( mGeos ); 03396 if ( numGeoms == -1 ) 03397 { 03398 return 1; 03399 } 03400 03401 bool isMultiGeom = false; 03402 int geosTypeId = GEOSGeomTypeId( mGeos ); 03403 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON ) 03404 { 03405 isMultiGeom = true; 03406 } 03407 03408 bool isLine = ( type() == QGis::Line ); 03409 03410 //polygon or multipolygon? 03411 if ( !isMultiGeom ) 03412 { 03413 GEOSGeometry* reshapedGeometry; 03414 if ( isLine ) 03415 { 03416 reshapedGeometry = reshapeLine( mGeos, reshapeLineGeos ); 03417 } 03418 else 03419 { 03420 reshapedGeometry = reshapePolygon( mGeos, reshapeLineGeos ); 03421 } 03422 03423 GEOSGeom_destroy( reshapeLineGeos ); 03424 if ( reshapedGeometry ) 03425 { 03426 GEOSGeom_destroy( mGeos ); 03427 mGeos = reshapedGeometry; 03428 mDirtyWkb = true; 03429 return 0; 03430 } 03431 else 03432 { 03433 return 1; 03434 } 03435 } 03436 else 03437 { 03438 //call reshape for each geometry part and replace mGeos with new geometry if reshape took place 03439 bool reshapeTookPlace = false; 03440 03441 GEOSGeometry* currentReshapeGeometry = 0; 03442 GEOSGeometry** newGeoms = new GEOSGeometry*[numGeoms]; 03443 03444 for ( int i = 0; i < numGeoms; ++i ) 03445 { 03446 if ( isLine ) 03447 { 03448 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN( mGeos, i ), reshapeLineGeos ); 03449 } 03450 else 03451 { 03452 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN( mGeos, i ), reshapeLineGeos ); 03453 } 03454 03455 if ( currentReshapeGeometry ) 03456 { 03457 newGeoms[i] = currentReshapeGeometry; 03458 reshapeTookPlace = true; 03459 } 03460 else 03461 { 03462 newGeoms[i] = GEOSGeom_clone( GEOSGetGeometryN( mGeos, i ) ); 03463 } 03464 } 03465 GEOSGeom_destroy( reshapeLineGeos ); 03466 03467 GEOSGeometry* newMultiGeom = 0; 03468 if ( isLine ) 03469 { 03470 newMultiGeom = GEOSGeom_createCollection( GEOS_MULTILINESTRING, newGeoms, numGeoms ); 03471 } 03472 else //multipolygon 03473 { 03474 newMultiGeom = GEOSGeom_createCollection( GEOS_MULTIPOLYGON, newGeoms, numGeoms ); 03475 } 03476 03477 delete[] newGeoms; 03478 if ( ! newMultiGeom ) 03479 { 03480 return 3; 03481 } 03482 03483 if ( reshapeTookPlace ) 03484 { 03485 GEOSGeom_destroy( mGeos ); 03486 mGeos = newMultiGeom; 03487 mDirtyWkb = true; 03488 return 0; 03489 } 03490 else 03491 { 03492 GEOSGeom_destroy( newMultiGeom ); 03493 return 1; 03494 } 03495 } 03496 } 03497 03498 int QgsGeometry::makeDifference( QgsGeometry* other ) 03499 { 03500 //make sure geos geometry is up to date 03501 if ( mDirtyGeos ) 03502 { 03503 exportWkbToGeos(); 03504 } 03505 03506 if ( !mGeos ) 03507 { 03508 return 1; 03509 } 03510 03511 if ( !GEOSisValid( mGeos ) ) 03512 { 03513 return 2; 03514 } 03515 03516 if ( !GEOSisSimple( mGeos ) ) 03517 { 03518 return 3; 03519 } 03520 03521 //convert other geometry to geos 03522 if ( other->mDirtyGeos ) 03523 { 03524 other->exportWkbToGeos(); 03525 } 03526 03527 if ( !other->mGeos ) 03528 { 03529 return 4; 03530 } 03531 03532 //make geometry::difference 03533 try 03534 { 03535 if ( GEOSIntersects( mGeos, other->mGeos ) ) 03536 { 03537 //check if multitype before and after 03538 bool multiType = isMultipart(); 03539 03540 mGeos = GEOSDifference( mGeos, other->mGeos ); 03541 mDirtyWkb = true; 03542 03543 if ( multiType && !isMultipart() ) 03544 { 03545 convertToMultiType(); 03546 exportWkbToGeos(); 03547 } 03548 } 03549 else 03550 { 03551 return 0; //nothing to do 03552 } 03553 } 03554 CATCH_GEOS( 5 ) 03555 03556 if ( !mGeos ) 03557 { 03558 mDirtyGeos = true; 03559 return 6; 03560 } 03561 03562 return 0; 03563 } 03564 03565 QgsRectangle QgsGeometry::boundingBox() 03566 { 03567 double xmin = std::numeric_limits<double>::max(); 03568 double ymin = std::numeric_limits<double>::max(); 03569 double xmax = -std::numeric_limits<double>::max(); 03570 double ymax = -std::numeric_limits<double>::max(); 03571 03572 double *x; 03573 double *y; 03574 int *nPoints; 03575 int *numRings; 03576 int *numPolygons; 03577 int numLineStrings; 03578 int idx, jdx, kdx; 03579 unsigned char *ptr; 03580 QgsPoint pt; 03581 QGis::WkbType wkbType; 03582 bool hasZValue = false; 03583 03584 // TODO: implement with GEOS 03585 if ( mDirtyWkb ) 03586 { 03587 exportGeosToWkb(); 03588 } 03589 03590 if ( !mGeometry ) 03591 { 03592 QgsDebugMsg( "WKB geometry not available!" ); 03593 return QgsRectangle( 0, 0, 0, 0 ); 03594 } 03595 03596 // consider endian when fetching feature type 03597 //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; //MH: Does not work for 25D geometries 03598 memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); 03599 switch ( wkbType ) 03600 { 03601 case QGis::WKBPoint25D: 03602 case QGis::WKBPoint: 03603 x = ( double * )( mGeometry + 5 ); 03604 y = ( double * )( mGeometry + 5 + sizeof( double ) ); 03605 if ( *x < xmin ) 03606 { 03607 xmin = *x; 03608 } 03609 if ( *x > xmax ) 03610 { 03611 xmax = *x; 03612 } 03613 if ( *y < ymin ) 03614 { 03615 ymin = *y; 03616 } 03617 if ( *y > ymax ) 03618 { 03619 ymax = *y; 03620 } 03621 break; 03622 case QGis::WKBMultiPoint25D: 03623 hasZValue = true; 03624 case QGis::WKBMultiPoint: 03625 { 03626 ptr = mGeometry + 1 + sizeof( int ); 03627 nPoints = ( int * ) ptr; 03628 ptr += sizeof( int ); 03629 for ( idx = 0; idx < *nPoints; idx++ ) 03630 { 03631 ptr += ( 1 + sizeof( int ) ); 03632 x = ( double * ) ptr; 03633 ptr += sizeof( double ); 03634 y = ( double * ) ptr; 03635 ptr += sizeof( double ); 03636 if ( hasZValue ) 03637 { 03638 ptr += sizeof( double ); 03639 } 03640 if ( *x < xmin ) 03641 { 03642 xmin = *x; 03643 } 03644 if ( *x > xmax ) 03645 { 03646 xmax = *x; 03647 } 03648 if ( *y < ymin ) 03649 { 03650 ymin = *y; 03651 } 03652 if ( *y > ymax ) 03653 { 03654 ymax = *y; 03655 } 03656 } 03657 break; 03658 } 03659 case QGis::WKBLineString25D: 03660 hasZValue = true; 03661 case QGis::WKBLineString: 03662 { 03663 // get number of points in the line 03664 ptr = mGeometry + 5; 03665 nPoints = ( int * ) ptr; 03666 ptr = mGeometry + 1 + 2 * sizeof( int ); 03667 for ( idx = 0; idx < *nPoints; idx++ ) 03668 { 03669 x = ( double * ) ptr; 03670 ptr += sizeof( double ); 03671 y = ( double * ) ptr; 03672 ptr += sizeof( double ); 03673 if ( hasZValue ) 03674 { 03675 ptr += sizeof( double ); 03676 } 03677 if ( *x < xmin ) 03678 { 03679 xmin = *x; 03680 } 03681 if ( *x > xmax ) 03682 { 03683 xmax = *x; 03684 } 03685 if ( *y < ymin ) 03686 { 03687 ymin = *y; 03688 } 03689 if ( *y > ymax ) 03690 { 03691 ymax = *y; 03692 } 03693 } 03694 break; 03695 } 03696 case QGis::WKBMultiLineString25D: 03697 hasZValue = true; 03698 case QGis::WKBMultiLineString: 03699 { 03700 numLineStrings = ( int )( mGeometry[5] ); 03701 ptr = mGeometry + 9; 03702 for ( jdx = 0; jdx < numLineStrings; jdx++ ) 03703 { 03704 // each of these is a wbklinestring so must handle as such 03705 ptr += 5; // skip type since we know its 2 03706 nPoints = ( int * ) ptr; 03707 ptr += sizeof( int ); 03708 for ( idx = 0; idx < *nPoints; idx++ ) 03709 { 03710 x = ( double * ) ptr; 03711 ptr += sizeof( double ); 03712 y = ( double * ) ptr; 03713 ptr += sizeof( double ); 03714 if ( hasZValue ) 03715 { 03716 ptr += sizeof( double ); 03717 } 03718 if ( *x < xmin ) 03719 { 03720 xmin = *x; 03721 } 03722 if ( *x > xmax ) 03723 { 03724 xmax = *x; 03725 } 03726 if ( *y < ymin ) 03727 { 03728 ymin = *y; 03729 } 03730 if ( *y > ymax ) 03731 { 03732 ymax = *y; 03733 } 03734 } 03735 } 03736 break; 03737 } 03738 case QGis::WKBPolygon25D: 03739 hasZValue = true; 03740 case QGis::WKBPolygon: 03741 { 03742 // get number of rings in the polygon 03743 numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); 03744 ptr = mGeometry + 1 + 2 * sizeof( int ); 03745 for ( idx = 0; idx < *numRings; idx++ ) 03746 { 03747 // get number of points in the ring 03748 nPoints = ( int * ) ptr; 03749 ptr += 4; 03750 for ( jdx = 0; jdx < *nPoints; jdx++ ) 03751 { 03752 // add points to a point array for drawing the polygon 03753 x = ( double * ) ptr; 03754 ptr += sizeof( double ); 03755 y = ( double * ) ptr; 03756 ptr += sizeof( double ); 03757 if ( hasZValue ) 03758 { 03759 ptr += sizeof( double ); 03760 } 03761 if ( *x < xmin ) 03762 { 03763 xmin = *x; 03764 } 03765 if ( *x > xmax ) 03766 { 03767 xmax = *x; 03768 } 03769 if ( *y < ymin ) 03770 { 03771 ymin = *y; 03772 } 03773 if ( *y > ymax ) 03774 { 03775 ymax = *y; 03776 } 03777 } 03778 } 03779 break; 03780 } 03781 case QGis::WKBMultiPolygon25D: 03782 hasZValue = true; 03783 case QGis::WKBMultiPolygon: 03784 { 03785 // get the number of polygons 03786 ptr = mGeometry + 5; 03787 numPolygons = ( int * ) ptr; 03788 ptr += 4; 03789 03790 for ( kdx = 0; kdx < *numPolygons; kdx++ ) 03791 { 03792 //skip the endian and mGeometry type info and 03793 // get number of rings in the polygon 03794 ptr += 5; 03795 numRings = ( int * ) ptr; 03796 ptr += 4; 03797 for ( idx = 0; idx < *numRings; idx++ ) 03798 { 03799 // get number of points in the ring 03800 nPoints = ( int * ) ptr; 03801 ptr += 4; 03802 for ( jdx = 0; jdx < *nPoints; jdx++ ) 03803 { 03804 // add points to a point array for drawing the polygon 03805 x = ( double * ) ptr; 03806 ptr += sizeof( double ); 03807 y = ( double * ) ptr; 03808 ptr += sizeof( double ); 03809 if ( hasZValue ) 03810 { 03811 ptr += sizeof( double ); 03812 } 03813 if ( *x < xmin ) 03814 { 03815 xmin = *x; 03816 } 03817 if ( *x > xmax ) 03818 { 03819 xmax = *x; 03820 } 03821 if ( *y < ymin ) 03822 { 03823 ymin = *y; 03824 } 03825 if ( *y > ymax ) 03826 { 03827 ymax = *y; 03828 } 03829 } 03830 } 03831 } 03832 break; 03833 } 03834 03835 default: 03836 QgsDebugMsg( QString( "Unknown WkbType %1 ENCOUNTERED" ).arg( wkbType ) ); 03837 return QgsRectangle( 0, 0, 0, 0 ); 03838 break; 03839 03840 } 03841 return QgsRectangle( xmin, ymin, xmax, ymax ); 03842 } 03843 03844 bool QgsGeometry::intersects( const QgsRectangle& r ) 03845 { 03846 QgsGeometry* g = fromRect( r ); 03847 bool res = intersects( g ); 03848 delete g; 03849 return res; 03850 } 03851 03852 bool QgsGeometry::intersects( QgsGeometry* geometry ) 03853 { 03854 try // geos might throw exception on error 03855 { 03856 // ensure that both geometries have geos geometry 03857 exportWkbToGeos(); 03858 geometry->exportWkbToGeos(); 03859 03860 if ( !mGeos || !geometry->mGeos ) 03861 { 03862 QgsDebugMsg( "GEOS geometry not available!" ); 03863 return false; 03864 } 03865 03866 return GEOSIntersects( mGeos, geometry->mGeos ); 03867 } 03868 CATCH_GEOS( false ) 03869 } 03870 03871 03872 bool QgsGeometry::contains( QgsPoint* p ) 03873 { 03874 exportWkbToGeos(); 03875 03876 if ( !mGeos ) 03877 { 03878 QgsDebugMsg( "GEOS geometry not available!" ); 03879 return false; 03880 } 03881 03882 GEOSGeometry *geosPoint = 0; 03883 03884 bool returnval = false; 03885 03886 try 03887 { 03888 geosPoint = createGeosPoint( *p ); 03889 returnval = GEOSContains( mGeos, geosPoint ); 03890 } 03891 catch ( GEOSException &e ) 03892 { 03893 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 03894 returnval = false; 03895 } 03896 03897 if ( geosPoint ) 03898 GEOSGeom_destroy( geosPoint ); 03899 03900 return returnval; 03901 } 03902 03903 bool QgsGeometry::geosRelOp( 03904 char( *op )( const GEOSGeometry*, const GEOSGeometry * ), 03905 QgsGeometry *a, 03906 QgsGeometry *b ) 03907 { 03908 try // geos might throw exception on error 03909 { 03910 // ensure that both geometries have geos geometry 03911 a->exportWkbToGeos(); 03912 b->exportWkbToGeos(); 03913 03914 if ( !a->mGeos || !b->mGeos ) 03915 { 03916 QgsDebugMsg( "GEOS geometry not available!" ); 03917 return false; 03918 } 03919 return op( a->mGeos, b->mGeos ); 03920 } 03921 CATCH_GEOS( false ) 03922 } 03923 03924 bool QgsGeometry::contains( QgsGeometry* geometry ) 03925 { 03926 return geosRelOp( GEOSContains, this, geometry ); 03927 } 03928 03929 bool QgsGeometry::disjoint( QgsGeometry* geometry ) 03930 { 03931 return geosRelOp( GEOSDisjoint, this, geometry ); 03932 } 03933 03934 bool QgsGeometry::equals( QgsGeometry* geometry ) 03935 { 03936 return geosRelOp( GEOSEquals, this, geometry ); 03937 } 03938 03939 bool QgsGeometry::touches( QgsGeometry* geometry ) 03940 { 03941 return geosRelOp( GEOSTouches, this, geometry ); 03942 } 03943 03944 bool QgsGeometry::overlaps( QgsGeometry* geometry ) 03945 { 03946 return geosRelOp( GEOSOverlaps, this, geometry ); 03947 } 03948 03949 bool QgsGeometry::within( QgsGeometry* geometry ) 03950 { 03951 return geosRelOp( GEOSWithin, this, geometry ); 03952 } 03953 03954 bool QgsGeometry::crosses( QgsGeometry* geometry ) 03955 { 03956 return geosRelOp( GEOSCrosses, this, geometry ); 03957 } 03958 03959 QString QgsGeometry::exportToWkt() 03960 { 03961 QgsDebugMsg( "entered." ); 03962 03963 // TODO: implement with GEOS 03964 if ( mDirtyWkb ) 03965 { 03966 exportGeosToWkb(); 03967 } 03968 03969 if ( !mGeometry || wkbSize() < 5 ) 03970 { 03971 QgsDebugMsg( "WKB geometry not available or too short!" ); 03972 return QString::null; 03973 } 03974 03975 QGis::WkbType wkbType; 03976 bool hasZValue = false; 03977 double *x, *y; 03978 03979 QString mWkt; // TODO: rename 03980 03981 // Will this really work when mGeometry[0] == 0 ???? I (gavin) think not. 03982 //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; 03983 memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); 03984 03985 switch ( wkbType ) 03986 { 03987 case QGis::WKBPoint25D: 03988 case QGis::WKBPoint: 03989 { 03990 mWkt += "POINT("; 03991 x = ( double * )( mGeometry + 5 ); 03992 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 03993 mWkt += " "; 03994 y = ( double * )( mGeometry + 5 + sizeof( double ) ); 03995 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 03996 mWkt += ")"; 03997 return mWkt; 03998 } 03999 04000 case QGis::WKBLineString25D: 04001 hasZValue = true; 04002 case QGis::WKBLineString: 04003 { 04004 QgsDebugMsg( "LINESTRING found" ); 04005 unsigned char *ptr; 04006 int *nPoints; 04007 int idx; 04008 04009 mWkt += "LINESTRING("; 04010 // get number of points in the line 04011 ptr = mGeometry + 5; 04012 nPoints = ( int * ) ptr; 04013 ptr = mGeometry + 1 + 2 * sizeof( int ); 04014 for ( idx = 0; idx < *nPoints; ++idx ) 04015 { 04016 if ( idx != 0 ) 04017 { 04018 mWkt += ", "; 04019 } 04020 x = ( double * ) ptr; 04021 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04022 mWkt += " "; 04023 ptr += sizeof( double ); 04024 y = ( double * ) ptr; 04025 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04026 ptr += sizeof( double ); 04027 if ( hasZValue ) 04028 { 04029 ptr += sizeof( double ); 04030 } 04031 } 04032 mWkt += ")"; 04033 return mWkt; 04034 } 04035 04036 case QGis::WKBPolygon25D: 04037 hasZValue = true; 04038 case QGis::WKBPolygon: 04039 { 04040 QgsDebugMsg( "POLYGON found" ); 04041 unsigned char *ptr; 04042 int idx, jdx; 04043 int *numRings, *nPoints; 04044 04045 mWkt += "POLYGON("; 04046 // get number of rings in the polygon 04047 numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); 04048 if ( !( *numRings ) ) // sanity check for zero rings in polygon 04049 { 04050 return QString(); 04051 } 04052 int *ringStart; // index of first point for each ring 04053 int *ringNumPoints; // number of points in each ring 04054 ringStart = new int[*numRings]; 04055 ringNumPoints = new int[*numRings]; 04056 ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring 04057 for ( idx = 0; idx < *numRings; idx++ ) 04058 { 04059 if ( idx != 0 ) 04060 { 04061 mWkt += ","; 04062 } 04063 mWkt += "("; 04064 // get number of points in the ring 04065 nPoints = ( int * ) ptr; 04066 ringNumPoints[idx] = *nPoints; 04067 ptr += 4; 04068 04069 for ( jdx = 0; jdx < *nPoints; jdx++ ) 04070 { 04071 if ( jdx != 0 ) 04072 { 04073 mWkt += ","; 04074 } 04075 x = ( double * ) ptr; 04076 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04077 mWkt += " "; 04078 ptr += sizeof( double ); 04079 y = ( double * ) ptr; 04080 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04081 ptr += sizeof( double ); 04082 if ( hasZValue ) 04083 { 04084 ptr += sizeof( double ); 04085 } 04086 } 04087 mWkt += ")"; 04088 } 04089 mWkt += ")"; 04090 delete [] ringStart; 04091 delete [] ringNumPoints; 04092 return mWkt; 04093 } 04094 04095 case QGis::WKBMultiPoint25D: 04096 hasZValue = true; 04097 case QGis::WKBMultiPoint: 04098 { 04099 unsigned char *ptr; 04100 int idx; 04101 int *nPoints; 04102 04103 mWkt += "MULTIPOINT("; 04104 nPoints = ( int* )( mGeometry + 5 ); 04105 ptr = mGeometry + 5 + sizeof( int ); 04106 for ( idx = 0; idx < *nPoints; ++idx ) 04107 { 04108 ptr += ( 1 + sizeof( int ) ); 04109 if ( idx != 0 ) 04110 { 04111 mWkt += ", "; 04112 } 04113 x = ( double * )( ptr ); 04114 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04115 mWkt += " "; 04116 ptr += sizeof( double ); 04117 y = ( double * )( ptr ); 04118 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04119 ptr += sizeof( double ); 04120 if ( hasZValue ) 04121 { 04122 ptr += sizeof( double ); 04123 } 04124 } 04125 mWkt += ")"; 04126 return mWkt; 04127 } 04128 04129 case QGis::WKBMultiLineString25D: 04130 hasZValue = true; 04131 case QGis::WKBMultiLineString: 04132 { 04133 QgsDebugMsg( "MULTILINESTRING found" ); 04134 unsigned char *ptr; 04135 int idx, jdx, numLineStrings; 04136 int *nPoints; 04137 04138 mWkt += "MULTILINESTRING("; 04139 numLineStrings = ( int )( mGeometry[5] ); 04140 ptr = mGeometry + 9; 04141 for ( jdx = 0; jdx < numLineStrings; jdx++ ) 04142 { 04143 if ( jdx != 0 ) 04144 { 04145 mWkt += ", "; 04146 } 04147 mWkt += "("; 04148 ptr += 5; // skip type since we know its 2 04149 nPoints = ( int * ) ptr; 04150 ptr += sizeof( int ); 04151 for ( idx = 0; idx < *nPoints; idx++ ) 04152 { 04153 if ( idx != 0 ) 04154 { 04155 mWkt += ", "; 04156 } 04157 x = ( double * ) ptr; 04158 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04159 ptr += sizeof( double ); 04160 mWkt += " "; 04161 y = ( double * ) ptr; 04162 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04163 ptr += sizeof( double ); 04164 if ( hasZValue ) 04165 { 04166 ptr += sizeof( double ); 04167 } 04168 } 04169 mWkt += ")"; 04170 } 04171 mWkt += ")"; 04172 return mWkt; 04173 } 04174 04175 case QGis::WKBMultiPolygon25D: 04176 hasZValue = true; 04177 case QGis::WKBMultiPolygon: 04178 { 04179 QgsDebugMsg( "MULTIPOLYGON found" ); 04180 unsigned char *ptr; 04181 int idx, jdx, kdx; 04182 int *numPolygons, *numRings, *nPoints; 04183 04184 mWkt += "MULTIPOLYGON("; 04185 ptr = mGeometry + 5; 04186 numPolygons = ( int * ) ptr; 04187 ptr = mGeometry + 9; 04188 for ( kdx = 0; kdx < *numPolygons; kdx++ ) 04189 { 04190 if ( kdx != 0 ) 04191 { 04192 mWkt += ","; 04193 } 04194 mWkt += "("; 04195 ptr += 5; 04196 numRings = ( int * ) ptr; 04197 ptr += 4; 04198 for ( idx = 0; idx < *numRings; idx++ ) 04199 { 04200 if ( idx != 0 ) 04201 { 04202 mWkt += ","; 04203 } 04204 mWkt += "("; 04205 nPoints = ( int * ) ptr; 04206 ptr += 4; 04207 for ( jdx = 0; jdx < *nPoints; jdx++ ) 04208 { 04209 if ( jdx != 0 ) 04210 { 04211 mWkt += ","; 04212 } 04213 x = ( double * ) ptr; 04214 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04215 ptr += sizeof( double ); 04216 mWkt += " "; 04217 y = ( double * ) ptr; 04218 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04219 ptr += sizeof( double ); 04220 if ( hasZValue ) 04221 { 04222 ptr += sizeof( double ); 04223 } 04224 } 04225 mWkt += ")"; 04226 } 04227 mWkt += ")"; 04228 } 04229 mWkt += ")"; 04230 return mWkt; 04231 } 04232 04233 default: 04234 QgsDebugMsg( "error: mGeometry type not recognized" ); 04235 return QString::null; 04236 } 04237 } 04238 04239 QString QgsGeometry::exportToGeoJSON() 04240 { 04241 QgsDebugMsg( "entered." ); 04242 04243 // TODO: implement with GEOS 04244 if ( mDirtyWkb ) 04245 { 04246 exportGeosToWkb(); 04247 } 04248 04249 if ( !mGeometry ) 04250 { 04251 QgsDebugMsg( "WKB geometry not available!" ); 04252 return QString::null; 04253 } 04254 04255 QGis::WkbType wkbType; 04256 bool hasZValue = false; 04257 double *x, *y; 04258 04259 QString mWkt; // TODO: rename 04260 04261 // Will this really work when mGeometry[0] == 0 ???? I (gavin) think not. 04262 //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; 04263 memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); 04264 04265 switch ( wkbType ) 04266 { 04267 case QGis::WKBPoint25D: 04268 case QGis::WKBPoint: 04269 { 04270 mWkt += "{ \"type\": \"Point\", \"coordinates\": ["; 04271 x = ( double * )( mGeometry + 5 ); 04272 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04273 mWkt += ", "; 04274 y = ( double * )( mGeometry + 5 + sizeof( double ) ); 04275 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04276 mWkt += "] }"; 04277 return mWkt; 04278 } 04279 04280 case QGis::WKBLineString25D: 04281 hasZValue = true; 04282 case QGis::WKBLineString: 04283 { 04284 QgsDebugMsg( "LINESTRING found" ); 04285 unsigned char *ptr; 04286 int *nPoints; 04287 int idx; 04288 04289 mWkt += "{ \"type\": \"LineString\", \"coordinates\": [ "; 04290 // get number of points in the line 04291 ptr = mGeometry + 5; 04292 nPoints = ( int * ) ptr; 04293 ptr = mGeometry + 1 + 2 * sizeof( int ); 04294 for ( idx = 0; idx < *nPoints; ++idx ) 04295 { 04296 if ( idx != 0 ) 04297 { 04298 mWkt += ", "; 04299 } 04300 mWkt += "["; 04301 x = ( double * ) ptr; 04302 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04303 mWkt += ", "; 04304 ptr += sizeof( double ); 04305 y = ( double * ) ptr; 04306 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04307 ptr += sizeof( double ); 04308 if ( hasZValue ) 04309 { 04310 ptr += sizeof( double ); 04311 } 04312 mWkt += "]"; 04313 } 04314 mWkt += " ] }"; 04315 return mWkt; 04316 } 04317 04318 case QGis::WKBPolygon25D: 04319 hasZValue = true; 04320 case QGis::WKBPolygon: 04321 { 04322 QgsDebugMsg( "POLYGON found" ); 04323 unsigned char *ptr; 04324 int idx, jdx; 04325 int *numRings, *nPoints; 04326 04327 mWkt += "{ \"type\": \"Polygon\", \"coordinates\": [ "; 04328 // get number of rings in the polygon 04329 numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); 04330 if ( !( *numRings ) ) // sanity check for zero rings in polygon 04331 { 04332 return QString(); 04333 } 04334 int *ringStart; // index of first point for each ring 04335 int *ringNumPoints; // number of points in each ring 04336 ringStart = new int[*numRings]; 04337 ringNumPoints = new int[*numRings]; 04338 ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring 04339 for ( idx = 0; idx < *numRings; idx++ ) 04340 { 04341 if ( idx != 0 ) 04342 { 04343 mWkt += ", "; 04344 } 04345 mWkt += "[ "; 04346 // get number of points in the ring 04347 nPoints = ( int * ) ptr; 04348 ringNumPoints[idx] = *nPoints; 04349 ptr += 4; 04350 04351 for ( jdx = 0; jdx < *nPoints; jdx++ ) 04352 { 04353 if ( jdx != 0 ) 04354 { 04355 mWkt += ", "; 04356 } 04357 mWkt += "["; 04358 x = ( double * ) ptr; 04359 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04360 mWkt += ", "; 04361 ptr += sizeof( double ); 04362 y = ( double * ) ptr; 04363 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04364 ptr += sizeof( double ); 04365 if ( hasZValue ) 04366 { 04367 ptr += sizeof( double ); 04368 } 04369 mWkt += "]"; 04370 } 04371 mWkt += " ]"; 04372 } 04373 mWkt += " ] }"; 04374 delete [] ringStart; 04375 delete [] ringNumPoints; 04376 return mWkt; 04377 } 04378 04379 case QGis::WKBMultiPoint25D: 04380 hasZValue = true; 04381 case QGis::WKBMultiPoint: 04382 { 04383 unsigned char *ptr; 04384 int idx; 04385 int *nPoints; 04386 04387 mWkt += "{ \"type\": \"MultiPoint\", \"coordinates\": [ "; 04388 nPoints = ( int* )( mGeometry + 5 ); 04389 ptr = mGeometry + 5 + sizeof( int ); 04390 for ( idx = 0; idx < *nPoints; ++idx ) 04391 { 04392 ptr += ( 1 + sizeof( int ) ); 04393 if ( idx != 0 ) 04394 { 04395 mWkt += ", "; 04396 } 04397 mWkt += "["; 04398 x = ( double * )( ptr ); 04399 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04400 mWkt += ", "; 04401 ptr += sizeof( double ); 04402 y = ( double * )( ptr ); 04403 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04404 ptr += sizeof( double ); 04405 if ( hasZValue ) 04406 { 04407 ptr += sizeof( double ); 04408 } 04409 mWkt += "]"; 04410 } 04411 mWkt += " ] }"; 04412 return mWkt; 04413 } 04414 04415 case QGis::WKBMultiLineString25D: 04416 hasZValue = true; 04417 case QGis::WKBMultiLineString: 04418 { 04419 QgsDebugMsg( "MULTILINESTRING found" ); 04420 unsigned char *ptr; 04421 int idx, jdx, numLineStrings; 04422 int *nPoints; 04423 04424 mWkt += "{ \"type\": \"MultiLineString\", \"coordinates\": [ "; 04425 numLineStrings = ( int )( mGeometry[5] ); 04426 ptr = mGeometry + 9; 04427 for ( jdx = 0; jdx < numLineStrings; jdx++ ) 04428 { 04429 if ( jdx != 0 ) 04430 { 04431 mWkt += ", "; 04432 } 04433 mWkt += "[ "; 04434 ptr += 5; // skip type since we know its 2 04435 nPoints = ( int * ) ptr; 04436 ptr += sizeof( int ); 04437 for ( idx = 0; idx < *nPoints; idx++ ) 04438 { 04439 if ( idx != 0 ) 04440 { 04441 mWkt += ", "; 04442 } 04443 mWkt += "["; 04444 x = ( double * ) ptr; 04445 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04446 ptr += sizeof( double ); 04447 mWkt += ", "; 04448 y = ( double * ) ptr; 04449 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04450 ptr += sizeof( double ); 04451 if ( hasZValue ) 04452 { 04453 ptr += sizeof( double ); 04454 } 04455 mWkt += "]"; 04456 } 04457 mWkt += " ]"; 04458 } 04459 mWkt += " ] }"; 04460 return mWkt; 04461 } 04462 04463 case QGis::WKBMultiPolygon25D: 04464 hasZValue = true; 04465 case QGis::WKBMultiPolygon: 04466 { 04467 QgsDebugMsg( "MULTIPOLYGON found" ); 04468 unsigned char *ptr; 04469 int idx, jdx, kdx; 04470 int *numPolygons, *numRings, *nPoints; 04471 04472 mWkt += "{ \"type\": \"MultiPolygon\", \"coordinates\": [ "; 04473 ptr = mGeometry + 5; 04474 numPolygons = ( int * ) ptr; 04475 ptr = mGeometry + 9; 04476 for ( kdx = 0; kdx < *numPolygons; kdx++ ) 04477 { 04478 if ( kdx != 0 ) 04479 { 04480 mWkt += ", "; 04481 } 04482 mWkt += "[ "; 04483 ptr += 5; 04484 numRings = ( int * ) ptr; 04485 ptr += 4; 04486 for ( idx = 0; idx < *numRings; idx++ ) 04487 { 04488 if ( idx != 0 ) 04489 { 04490 mWkt += ", "; 04491 } 04492 mWkt += "[ "; 04493 nPoints = ( int * ) ptr; 04494 ptr += 4; 04495 for ( jdx = 0; jdx < *nPoints; jdx++ ) 04496 { 04497 if ( jdx != 0 ) 04498 { 04499 mWkt += ", "; 04500 } 04501 mWkt += "["; 04502 x = ( double * ) ptr; 04503 mWkt += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04504 ptr += sizeof( double ); 04505 mWkt += ", "; 04506 y = ( double * ) ptr; 04507 mWkt += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 04508 ptr += sizeof( double ); 04509 if ( hasZValue ) 04510 { 04511 ptr += sizeof( double ); 04512 } 04513 mWkt += "]"; 04514 } 04515 mWkt += " ]"; 04516 } 04517 mWkt += " ]"; 04518 } 04519 mWkt += " ] }"; 04520 return mWkt; 04521 } 04522 04523 default: 04524 QgsDebugMsg( "error: mGeometry type not recognized" ); 04525 return QString::null; 04526 } 04527 } 04528 04529 04530 bool QgsGeometry::exportWkbToGeos() 04531 { 04532 QgsDebugMsgLevel( "entered.", 3 ); 04533 04534 if ( !mDirtyGeos ) 04535 { 04536 // No need to convert again 04537 return true; 04538 } 04539 04540 if ( mGeos ) 04541 { 04542 GEOSGeom_destroy( mGeos ); 04543 mGeos = 0; 04544 } 04545 04546 // this probably shouldn't return true 04547 if ( !mGeometry ) 04548 { 04549 // no WKB => no GEOS 04550 mDirtyGeos = false; 04551 return true; 04552 } 04553 04554 double *x; 04555 double *y; 04556 int *nPoints; 04557 int *numRings; 04558 int *numPolygons; 04559 int *numLineStrings; 04560 int idx, jdx, kdx; 04561 unsigned char *ptr; 04562 QgsPoint pt; 04563 QGis::WkbType wkbtype; 04564 bool hasZValue = false; 04565 04566 //wkbtype = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; 04567 memcpy( &wkbtype, &( mGeometry[1] ), sizeof( int ) ); 04568 04569 try 04570 { 04571 switch ( wkbtype ) 04572 { 04573 case QGis::WKBPoint25D: 04574 case QGis::WKBPoint: 04575 { 04576 x = ( double * )( mGeometry + 5 ); 04577 y = ( double * )( mGeometry + 5 + sizeof( double ) ); 04578 04579 mGeos = createGeosPoint( QgsPoint( *x, *y ) ); 04580 mDirtyGeos = false; 04581 break; 04582 } 04583 04584 case QGis::WKBMultiPoint25D: 04585 hasZValue = true; 04586 case QGis::WKBMultiPoint: 04587 { 04588 QVector<GEOSGeometry *> points; 04589 04590 ptr = mGeometry + 5; 04591 nPoints = ( int * ) ptr; 04592 ptr = mGeometry + 1 + 2 * sizeof( int ); 04593 for ( idx = 0; idx < *nPoints; idx++ ) 04594 { 04595 ptr += ( 1 + sizeof( int ) ); 04596 x = ( double * ) ptr; 04597 ptr += sizeof( double ); 04598 y = ( double * ) ptr; 04599 ptr += sizeof( double ); 04600 if ( hasZValue ) 04601 { 04602 ptr += sizeof( double ); 04603 } 04604 points << createGeosPoint( QgsPoint( *x, *y ) ); 04605 } 04606 mGeos = createGeosCollection( GEOS_MULTIPOINT, points ); 04607 mDirtyGeos = false; 04608 break; 04609 } 04610 04611 case QGis::WKBLineString25D: 04612 hasZValue = true; 04613 case QGis::WKBLineString: 04614 { 04615 QgsDebugMsgLevel( "Linestring found", 3 ); 04616 04617 QgsPolyline sequence; 04618 04619 ptr = mGeometry + 5; 04620 nPoints = ( int * ) ptr; 04621 ptr = mGeometry + 1 + 2 * sizeof( int ); 04622 for ( idx = 0; idx < *nPoints; idx++ ) 04623 { 04624 x = ( double * ) ptr; 04625 ptr += sizeof( double ); 04626 y = ( double * ) ptr; 04627 ptr += sizeof( double ); 04628 if ( hasZValue ) 04629 { 04630 ptr += sizeof( double ); 04631 } 04632 04633 sequence << QgsPoint( *x, *y ); 04634 } 04635 mDirtyGeos = false; 04636 mGeos = createGeosLineString( sequence ); 04637 break; 04638 } 04639 04640 case QGis::WKBMultiLineString25D: 04641 hasZValue = true; 04642 case QGis::WKBMultiLineString: 04643 { 04644 QVector<GEOSGeometry*> lines; 04645 numLineStrings = ( int* )( mGeometry + 5 ); 04646 ptr = ( mGeometry + 9 ); 04647 for ( jdx = 0; jdx < *numLineStrings; jdx++ ) 04648 { 04649 QgsPolyline sequence; 04650 04651 // each of these is a wbklinestring so must handle as such 04652 ptr += 5; // skip type since we know its 2 04653 nPoints = ( int * ) ptr; 04654 ptr += sizeof( int ); 04655 for ( idx = 0; idx < *nPoints; idx++ ) 04656 { 04657 x = ( double * ) ptr; 04658 ptr += sizeof( double ); 04659 y = ( double * ) ptr; 04660 ptr += sizeof( double ); 04661 if ( hasZValue ) 04662 { 04663 ptr += sizeof( double ); 04664 } 04665 sequence << QgsPoint( *x, *y ); 04666 } 04667 lines << createGeosLineString( sequence ); 04668 } 04669 mGeos = createGeosCollection( GEOS_MULTILINESTRING, lines ); 04670 mDirtyGeos = false; 04671 break; 04672 } 04673 04674 case QGis::WKBPolygon25D: 04675 hasZValue = true; 04676 case QGis::WKBPolygon: 04677 { 04678 QgsDebugMsgLevel( "Polygon found", 3 ); 04679 04680 // get number of rings in the polygon 04681 numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); 04682 ptr = mGeometry + 1 + 2 * sizeof( int ); 04683 04684 QVector<GEOSGeometry*> rings; 04685 04686 for ( idx = 0; idx < *numRings; idx++ ) 04687 { 04688 //QgsDebugMsg("Ring nr: "+QString::number(idx)); 04689 04690 QgsPolyline sequence; 04691 04692 // get number of points in the ring 04693 nPoints = ( int * ) ptr; 04694 ptr += 4; 04695 for ( jdx = 0; jdx < *nPoints; jdx++ ) 04696 { 04697 // add points to a point array for drawing the polygon 04698 x = ( double * ) ptr; 04699 ptr += sizeof( double ); 04700 y = ( double * ) ptr; 04701 ptr += sizeof( double ); 04702 if ( hasZValue ) 04703 { 04704 ptr += sizeof( double ); 04705 } 04706 sequence << QgsPoint( *x, *y ); 04707 } 04708 04709 rings << createGeosLinearRing( sequence ); 04710 } 04711 mGeos = createGeosPolygon( rings ); 04712 mDirtyGeos = false; 04713 break; 04714 } 04715 04716 case QGis::WKBMultiPolygon25D: 04717 hasZValue = true; 04718 case QGis::WKBMultiPolygon: 04719 { 04720 QgsDebugMsgLevel( "Multipolygon found", 3 ); 04721 04722 QVector<GEOSGeometry*> polygons; 04723 04724 // get the number of polygons 04725 ptr = mGeometry + 5; 04726 numPolygons = ( int * ) ptr; 04727 ptr = mGeometry + 9; 04728 for ( kdx = 0; kdx < *numPolygons; kdx++ ) 04729 { 04730 //QgsDebugMsg("Polygon nr: "+QString::number(kdx)); 04731 QVector<GEOSGeometry*> rings; 04732 04733 //skip the endian and mGeometry type info and 04734 // get number of rings in the polygon 04735 ptr += 5; 04736 numRings = ( int * ) ptr; 04737 ptr += 4; 04738 for ( idx = 0; idx < *numRings; idx++ ) 04739 { 04740 //QgsDebugMsg("Ring nr: "+QString::number(idx)); 04741 04742 QgsPolyline sequence; 04743 04744 // get number of points in the ring 04745 nPoints = ( int * ) ptr; 04746 ptr += 4; 04747 for ( jdx = 0; jdx < *nPoints; jdx++ ) 04748 { 04749 // add points to a point array for drawing the polygon 04750 x = ( double * ) ptr; 04751 ptr += sizeof( double ); 04752 y = ( double * ) ptr; 04753 ptr += sizeof( double ); 04754 if ( hasZValue ) 04755 { 04756 ptr += sizeof( double ); 04757 } 04758 sequence << QgsPoint( *x, *y ); 04759 } 04760 04761 rings << createGeosLinearRing( sequence ); 04762 } 04763 04764 polygons << createGeosPolygon( rings ); 04765 } 04766 mGeos = createGeosCollection( GEOS_MULTIPOLYGON, polygons ); 04767 mDirtyGeos = false; 04768 break; 04769 } 04770 04771 default: 04772 return false; 04773 } 04774 } 04775 CATCH_GEOS( false ) 04776 04777 return true; 04778 } 04779 04780 bool QgsGeometry::exportGeosToWkb() 04781 { 04782 //QgsDebugMsg("entered."); 04783 if ( !mDirtyWkb ) 04784 { 04785 // No need to convert again 04786 return true; 04787 } 04788 04789 // clear the WKB, ready to replace with the new one 04790 if ( mGeometry ) 04791 { 04792 delete [] mGeometry; 04793 mGeometry = 0; 04794 } 04795 04796 if ( !mGeos ) 04797 { 04798 // GEOS is null, therefore WKB is null. 04799 mDirtyWkb = false; 04800 return true; 04801 } 04802 04803 // set up byteOrder 04804 char byteOrder = QgsApplication::endian(); 04805 04806 switch ( GEOSGeomTypeId( mGeos ) ) 04807 { 04808 case GEOS_POINT: // a point 04809 { 04810 mGeometrySize = 1 + // sizeof(byte) 04811 4 + // sizeof(uint32) 04812 2 * sizeof( double ); 04813 mGeometry = new unsigned char[mGeometrySize]; 04814 04815 // assign byteOrder 04816 memcpy( mGeometry, &byteOrder, 1 ); 04817 04818 // assign wkbType 04819 int wkbType = QGis::WKBPoint; 04820 memcpy( mGeometry + 1, &wkbType, 4 ); 04821 04822 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( mGeos ); 04823 04824 double x, y; 04825 GEOSCoordSeq_getX( cs, 0, &x ); 04826 GEOSCoordSeq_getY( cs, 0, &y ); 04827 04828 memcpy( mGeometry + 5, &x, sizeof( double ) ); 04829 memcpy( mGeometry + 13, &y, sizeof( double ) ); 04830 04831 mDirtyWkb = false; 04832 return true; 04833 } // case GEOS_GEOM::GEOS_POINT 04834 04835 case GEOS_LINESTRING: // a linestring 04836 { 04837 //QgsDebugMsg("Got a geos::GEOS_LINESTRING."); 04838 04839 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( mGeos ); 04840 unsigned int numPoints; 04841 GEOSCoordSeq_getSize( cs, &numPoints ); 04842 04843 // allocate some space for the WKB 04844 mGeometrySize = 1 + // sizeof(byte) 04845 4 + // sizeof(uint32) 04846 4 + // sizeof(uint32) 04847 (( sizeof( double ) + 04848 sizeof( double ) ) * numPoints ); 04849 04850 mGeometry = new unsigned char[mGeometrySize]; 04851 04852 unsigned char* ptr = mGeometry; 04853 04854 // assign byteOrder 04855 memcpy( ptr, &byteOrder, 1 ); 04856 ptr += 1; 04857 04858 // assign wkbType 04859 int wkbType = QGis::WKBLineString; 04860 memcpy( ptr, &wkbType, 4 ); 04861 ptr += 4; 04862 04863 // assign numPoints 04864 memcpy( ptr, &numPoints, 4 ); 04865 ptr += 4; 04866 04867 const GEOSCoordSequence *sequence = GEOSGeom_getCoordSeq( mGeos ); 04868 04869 // assign points 04870 for ( unsigned int n = 0; n < numPoints; n++ ) 04871 { 04872 // assign x 04873 GEOSCoordSeq_getX( sequence, n, ( double * )ptr ); 04874 ptr += sizeof( double ); 04875 04876 // assign y 04877 GEOSCoordSeq_getY( sequence, n, ( double * )ptr ); 04878 ptr += sizeof( double ); 04879 } 04880 04881 mDirtyWkb = false; 04882 return true; 04883 04884 // TODO: Deal with endian-ness 04885 } // case GEOS_GEOM::GEOS_LINESTRING 04886 04887 case GEOS_LINEARRING: // a linear ring (linestring with 1st point == last point) 04888 { 04889 // TODO 04890 break; 04891 } // case GEOS_GEOM::GEOS_LINEARRING 04892 04893 case GEOS_POLYGON: // a polygon 04894 { 04895 int geometrySize; 04896 unsigned int nPointsInRing = 0; 04897 04898 //first calculate the geometry size 04899 geometrySize = 1 + 2 * sizeof( int ); //endian, type, number of rings 04900 const GEOSGeometry *theRing = GEOSGetExteriorRing( mGeos ); 04901 if ( theRing ) 04902 { 04903 geometrySize += sizeof( int ); 04904 geometrySize += getNumGeosPoints( theRing ) * 2 * sizeof( double ); 04905 } 04906 for ( int i = 0; i < GEOSGetNumInteriorRings( mGeos ); ++i ) 04907 { 04908 geometrySize += sizeof( int ); //number of points in ring 04909 theRing = GEOSGetInteriorRingN( mGeos, i ); 04910 if ( theRing ) 04911 { 04912 geometrySize += getNumGeosPoints( theRing ) * 2 * sizeof( double ); 04913 } 04914 } 04915 04916 mGeometry = new unsigned char[geometrySize]; 04917 mGeometrySize = geometrySize; 04918 04919 //then fill the geometry itself into the wkb 04920 int position = 0; 04921 // assign byteOrder 04922 memcpy( mGeometry, &byteOrder, 1 ); 04923 position += 1; 04924 int wkbtype = QGis::WKBPolygon; 04925 memcpy( &mGeometry[position], &wkbtype, sizeof( int ) ); 04926 position += sizeof( int ); 04927 int nRings = GEOSGetNumInteriorRings( mGeos ) + 1; 04928 memcpy( &mGeometry[position], &nRings, sizeof( int ) ); 04929 position += sizeof( int ); 04930 04931 //exterior ring first 04932 theRing = GEOSGetExteriorRing( mGeos ); 04933 if ( theRing ) 04934 { 04935 nPointsInRing = getNumGeosPoints( theRing ); 04936 memcpy( &mGeometry[position], &nPointsInRing, sizeof( int ) ); 04937 position += sizeof( int ); 04938 04939 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( theRing ); 04940 unsigned int n; 04941 GEOSCoordSeq_getSize( cs, &n ); 04942 04943 for ( unsigned int j = 0; j < n; ++j ) 04944 { 04945 GEOSCoordSeq_getX( cs, j, ( double * )&mGeometry[position] ); 04946 position += sizeof( double ); 04947 GEOSCoordSeq_getY( cs, j, ( double * )&mGeometry[position] ); 04948 position += sizeof( double ); 04949 } 04950 } 04951 04952 //interior rings after 04953 for ( int i = 0; i < GEOSGetNumInteriorRings( mGeos ); i++ ) 04954 { 04955 theRing = GEOSGetInteriorRingN( mGeos, i ); 04956 04957 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( theRing ); 04958 GEOSCoordSeq_getSize( cs, &nPointsInRing ); 04959 04960 memcpy( &mGeometry[position], &nPointsInRing, sizeof( int ) ); 04961 position += sizeof( int ); 04962 04963 for ( unsigned int j = 0; j < nPointsInRing; j++ ) 04964 { 04965 GEOSCoordSeq_getX( cs, j, ( double * )&mGeometry[position] ); 04966 position += sizeof( double ); 04967 GEOSCoordSeq_getY( cs, j, ( double * )&mGeometry[position] ); 04968 position += sizeof( double ); 04969 } 04970 } 04971 mDirtyWkb = false; 04972 return true; 04973 } // case GEOS_GEOM::GEOS_POLYGON 04974 break; 04975 04976 case GEOS_MULTIPOINT: // a collection of points 04977 { 04978 // determine size of geometry 04979 int geometrySize = 1 + 2 * sizeof( int ); 04980 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ ) 04981 { 04982 geometrySize += 1 + sizeof( int ) + 2 * sizeof( double ); 04983 } 04984 04985 mGeometry = new unsigned char[geometrySize]; 04986 mGeometrySize = geometrySize; 04987 int wkbPosition = 0; //current position in the byte array 04988 04989 memcpy( mGeometry, &byteOrder, 1 ); 04990 wkbPosition += 1; 04991 int wkbtype = QGis::WKBMultiPoint; 04992 memcpy( &mGeometry[wkbPosition], &wkbtype, sizeof( int ) ); 04993 wkbPosition += sizeof( int ); 04994 int numPoints = GEOSGetNumGeometries( mGeos ); 04995 memcpy( &mGeometry[wkbPosition], &numPoints, sizeof( int ) ); 04996 wkbPosition += sizeof( int ); 04997 04998 int pointType = QGis::WKBPoint; 04999 const GEOSGeometry *currentPoint = 0; 05000 05001 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ ) 05002 { 05003 //copy endian and point type 05004 memcpy( &mGeometry[wkbPosition], &byteOrder, 1 ); 05005 wkbPosition += 1; 05006 memcpy( &mGeometry[wkbPosition], &pointType, sizeof( int ) ); 05007 wkbPosition += sizeof( int ); 05008 05009 currentPoint = GEOSGetGeometryN( mGeos, i ); 05010 05011 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( currentPoint ); 05012 05013 GEOSCoordSeq_getX( cs, 0, ( double* )&mGeometry[wkbPosition] ); 05014 wkbPosition += sizeof( double ); 05015 GEOSCoordSeq_getY( cs, 0, ( double* )&mGeometry[wkbPosition] ); 05016 wkbPosition += sizeof( double ); 05017 } 05018 mDirtyWkb = false; 05019 return true; 05020 } // case GEOS_GEOM::GEOS_MULTIPOINT 05021 05022 case GEOS_MULTILINESTRING: // a collection of linestrings 05023 { 05024 // determine size of geometry 05025 int geometrySize = 1 + 2 * sizeof( int ); 05026 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ ) 05027 { 05028 geometrySize += 1 + 2 * sizeof( int ); 05029 geometrySize += getNumGeosPoints( GEOSGetGeometryN( mGeos, i ) ) * 2 * sizeof( double ); 05030 } 05031 05032 mGeometry = new unsigned char[geometrySize]; 05033 mGeometrySize = geometrySize; 05034 int wkbPosition = 0; //current position in the byte array 05035 05036 memcpy( mGeometry, &byteOrder, 1 ); 05037 wkbPosition += 1; 05038 int wkbtype = QGis::WKBMultiLineString; 05039 memcpy( &mGeometry[wkbPosition], &wkbtype, sizeof( int ) ); 05040 wkbPosition += sizeof( int ); 05041 int numLines = GEOSGetNumGeometries( mGeos ); 05042 memcpy( &mGeometry[wkbPosition], &numLines, sizeof( int ) ); 05043 wkbPosition += sizeof( int ); 05044 05045 //loop over lines 05046 int lineType = QGis::WKBLineString; 05047 const GEOSCoordSequence *cs = 0; 05048 unsigned int lineSize; 05049 05050 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ ) 05051 { 05052 //endian and type WKBLineString 05053 memcpy( &mGeometry[wkbPosition], &byteOrder, 1 ); 05054 wkbPosition += 1; 05055 memcpy( &mGeometry[wkbPosition], &lineType, sizeof( int ) ); 05056 wkbPosition += sizeof( int ); 05057 05058 cs = GEOSGeom_getCoordSeq( GEOSGetGeometryN( mGeos, i ) ); 05059 05060 //line size 05061 GEOSCoordSeq_getSize( cs, &lineSize ); 05062 memcpy( &mGeometry[wkbPosition], &lineSize, sizeof( int ) ); 05063 wkbPosition += sizeof( int ); 05064 05065 //vertex coordinates 05066 for ( unsigned int j = 0; j < lineSize; ++j ) 05067 { 05068 GEOSCoordSeq_getX( cs, j, ( double* )&mGeometry[wkbPosition] ); 05069 wkbPosition += sizeof( double ); 05070 GEOSCoordSeq_getY( cs, j, ( double* )&mGeometry[wkbPosition] ); 05071 wkbPosition += sizeof( double ); 05072 } 05073 } 05074 mDirtyWkb = false; 05075 return true; 05076 } // case GEOS_GEOM::GEOS_MULTILINESTRING 05077 05078 case GEOS_MULTIPOLYGON: // a collection of polygons 05079 { 05080 //first determine size of geometry 05081 int geometrySize = 1 + ( 2 * sizeof( int ) ); //endian, type, number of polygons 05082 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ ) 05083 { 05084 const GEOSGeometry *thePoly = GEOSGetGeometryN( mGeos, i ); 05085 geometrySize += 1 + 2 * sizeof( int ); //endian, type, number of rings 05086 //exterior ring 05087 geometrySize += sizeof( int ); //number of points in exterior ring 05088 const GEOSGeometry *exRing = GEOSGetExteriorRing( thePoly ); 05089 geometrySize += 2 * sizeof( double ) * getNumGeosPoints( exRing ); 05090 05091 const GEOSGeometry *intRing = 0; 05092 for ( int j = 0; j < GEOSGetNumInteriorRings( thePoly ); j++ ) 05093 { 05094 geometrySize += sizeof( int ); //number of points in ring 05095 intRing = GEOSGetInteriorRingN( thePoly, j ); 05096 geometrySize += 2 * sizeof( double ) * getNumGeosPoints( intRing ); 05097 } 05098 } 05099 05100 mGeometry = new unsigned char[geometrySize]; 05101 mGeometrySize = geometrySize; 05102 int wkbPosition = 0; //current position in the byte array 05103 05104 memcpy( mGeometry, &byteOrder, 1 ); 05105 wkbPosition += 1; 05106 int wkbtype = QGis::WKBMultiPolygon; 05107 memcpy( &mGeometry[wkbPosition], &wkbtype, sizeof( int ) ); 05108 wkbPosition += sizeof( int ); 05109 int numPolygons = GEOSGetNumGeometries( mGeos ); 05110 memcpy( &mGeometry[wkbPosition], &numPolygons, sizeof( int ) ); 05111 wkbPosition += sizeof( int ); 05112 05113 //loop over polygons 05114 for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ ) 05115 { 05116 const GEOSGeometry *thePoly = GEOSGetGeometryN( mGeos, i ); 05117 memcpy( &mGeometry[wkbPosition], &byteOrder, 1 ); 05118 wkbPosition += 1; 05119 int polygonType = QGis::WKBPolygon; 05120 memcpy( &mGeometry[wkbPosition], &polygonType, sizeof( int ) ); 05121 wkbPosition += sizeof( int ); 05122 int numRings = GEOSGetNumInteriorRings( thePoly ) + 1; 05123 memcpy( &mGeometry[wkbPosition], &numRings, sizeof( int ) ); 05124 wkbPosition += sizeof( int ); 05125 05126 //exterior ring 05127 const GEOSGeometry *theRing = GEOSGetExteriorRing( thePoly ); 05128 int nPointsInRing = getNumGeosPoints( theRing ); 05129 memcpy( &mGeometry[wkbPosition], &nPointsInRing, sizeof( int ) ); 05130 wkbPosition += sizeof( int ); 05131 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( theRing ); 05132 05133 for ( int k = 0; k < nPointsInRing; ++k ) 05134 { 05135 GEOSCoordSeq_getX( cs, k, ( double * )&mGeometry[wkbPosition] ); 05136 wkbPosition += sizeof( double ); 05137 GEOSCoordSeq_getY( cs, k, ( double * )&mGeometry[wkbPosition] ); 05138 wkbPosition += sizeof( double ); 05139 } 05140 05141 //interior rings 05142 for ( int j = 0; j < GEOSGetNumInteriorRings( thePoly ); j++ ) 05143 { 05144 theRing = GEOSGetInteriorRingN( thePoly, j ); 05145 nPointsInRing = getNumGeosPoints( theRing ); 05146 memcpy( &mGeometry[wkbPosition], &nPointsInRing, sizeof( int ) ); 05147 wkbPosition += sizeof( int ); 05148 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( theRing ); 05149 05150 for ( int k = 0; k < nPointsInRing; ++k ) 05151 { 05152 GEOSCoordSeq_getX( cs, k, ( double * )&mGeometry[wkbPosition] ); 05153 wkbPosition += sizeof( double ); 05154 GEOSCoordSeq_getY( cs, k, ( double * )&mGeometry[wkbPosition] ); 05155 wkbPosition += sizeof( double ); 05156 } 05157 } 05158 } 05159 mDirtyWkb = false; 05160 return true; 05161 } // case GEOS_GEOM::GEOS_MULTIPOLYGON 05162 05163 case GEOS_GEOMETRYCOLLECTION: // a collection of heterogeneus geometries 05164 { 05165 // TODO 05166 QgsDebugMsg( "geometry collection - not supported" ); 05167 break; 05168 } // case GEOS_GEOM::GEOS_GEOMETRYCOLLECTION 05169 05170 } // switch (mGeos->getGeometryTypeId()) 05171 05172 return false; 05173 } 05174 05175 bool QgsGeometry::convertToMultiType() 05176 { 05177 if ( !mGeometry ) 05178 { 05179 return false; 05180 } 05181 05182 QGis::WkbType geomType = wkbType(); 05183 05184 if ( geomType == QGis::WKBMultiPoint || geomType == QGis::WKBMultiPoint25D || 05185 geomType == QGis::WKBMultiLineString || geomType == QGis::WKBMultiLineString25D || 05186 geomType == QGis::WKBMultiPolygon || geomType == QGis::WKBMultiPolygon25D || geomType == QGis::WKBUnknown ) 05187 { 05188 return false; //no need to convert 05189 } 05190 05191 int newGeomSize = mGeometrySize + 1 + 2 * sizeof( int ); //endian: 1, multitype: sizeof(int), number of geometries: sizeof(int) 05192 unsigned char* newGeometry = new unsigned char[newGeomSize]; 05193 05194 int currentWkbPosition = 0; 05195 //copy endian 05196 char byteOrder = QgsApplication::endian(); 05197 memcpy( &newGeometry[currentWkbPosition], &byteOrder, 1 ); 05198 currentWkbPosition += 1; 05199 05200 //copy wkbtype 05201 //todo 05202 QGis::WkbType newMultiType; 05203 switch ( geomType ) 05204 { 05205 case QGis::WKBPoint: 05206 newMultiType = QGis::WKBMultiPoint; 05207 break; 05208 case QGis::WKBPoint25D: 05209 newMultiType = QGis::WKBMultiPoint25D; 05210 break; 05211 case QGis::WKBLineString: 05212 newMultiType = QGis::WKBMultiLineString; 05213 break; 05214 case QGis::WKBLineString25D: 05215 newMultiType = QGis::WKBMultiLineString25D; 05216 break; 05217 case QGis::WKBPolygon: 05218 newMultiType = QGis::WKBMultiPolygon; 05219 break; 05220 case QGis::WKBPolygon25D: 05221 newMultiType = QGis::WKBMultiPolygon25D; 05222 break; 05223 default: 05224 delete newGeometry; 05225 return false; 05226 } 05227 memcpy( &newGeometry[currentWkbPosition], &newMultiType, sizeof( int ) ); 05228 currentWkbPosition += sizeof( int ); 05229 05230 //copy number of geometries 05231 int nGeometries = 1; 05232 memcpy( &newGeometry[currentWkbPosition], &nGeometries, sizeof( int ) ); 05233 currentWkbPosition += sizeof( int ); 05234 05235 //copy the existing single geometry 05236 memcpy( &newGeometry[currentWkbPosition], mGeometry, mGeometrySize ); 05237 05238 delete [] mGeometry; 05239 mGeometry = newGeometry; 05240 mGeometrySize = newGeomSize; 05241 mDirtyGeos = true; 05242 return true; 05243 } 05244 05245 void QgsGeometry::translateVertex( int& wkbPosition, double dx, double dy, bool hasZValue ) 05246 { 05247 double x, y, translated_x, translated_y; 05248 05249 //x-coordinate 05250 x = *(( double * )( &( mGeometry[wkbPosition] ) ) ); 05251 translated_x = x + dx; 05252 memcpy( &( mGeometry[wkbPosition] ), &translated_x, sizeof( double ) ); 05253 wkbPosition += sizeof( double ); 05254 05255 //y-coordinate 05256 y = *(( double * )( &( mGeometry[wkbPosition] ) ) ); 05257 translated_y = y + dy; 05258 memcpy( &( mGeometry[wkbPosition] ), &translated_y, sizeof( double ) ); 05259 wkbPosition += sizeof( double ); 05260 05261 if ( hasZValue ) 05262 { 05263 wkbPosition += sizeof( double ); 05264 } 05265 } 05266 05267 void QgsGeometry::transformVertex( int& wkbPosition, const QgsCoordinateTransform& ct, bool hasZValue ) 05268 { 05269 double x, y, z; 05270 05271 05272 x = *(( double * )( &( mGeometry[wkbPosition] ) ) ); 05273 y = *(( double * )( &( mGeometry[wkbPosition + sizeof( double )] ) ) ); 05274 z = 0.0; // Ignore Z for now. 05275 05276 ct.transformInPlace( x, y, z ); 05277 05278 // new x-coordinate 05279 memcpy( &( mGeometry[wkbPosition] ), &x, sizeof( double ) ); 05280 wkbPosition += sizeof( double ); 05281 05282 // new y-coordinate 05283 memcpy( &( mGeometry[wkbPosition] ), &y, sizeof( double ) ); 05284 wkbPosition += sizeof( double ); 05285 05286 if ( hasZValue ) 05287 { 05288 wkbPosition += sizeof( double ); 05289 } 05290 } 05291 05292 int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries ) 05293 { 05294 if ( !splitLine ) 05295 { 05296 return 2; 05297 } 05298 05299 if ( mDirtyGeos ) 05300 { 05301 exportWkbToGeos(); 05302 } 05303 05304 if ( !mGeos ) 05305 { 05306 return 5; 05307 } 05308 05309 //first test if linestring intersects geometry. If not, return straight away 05310 if ( !GEOSIntersects( splitLine, mGeos ) ) 05311 { 05312 return 1; 05313 } 05314 05315 //check that split line has no linear intersection 05316 int linearIntersect = GEOSRelatePattern( mGeos, splitLine, "1********" ); 05317 if ( linearIntersect > 0 ) 05318 { 05319 return 3; 05320 } 05321 05322 GEOSGeometry* splitGeom = GEOSDifference( mGeos, splitLine ); 05323 QVector<GEOSGeometry*> lineGeoms; 05324 05325 int splitType = GEOSGeomTypeId( splitGeom ); 05326 if ( splitType == GEOS_MULTILINESTRING ) 05327 { 05328 int nGeoms = GEOSGetNumGeometries( splitGeom ); 05329 for ( int i = 0; i < nGeoms; ++i ) 05330 { 05331 lineGeoms << GEOSGeom_clone( GEOSGetGeometryN( splitGeom, i ) ); 05332 } 05333 } 05334 else 05335 { 05336 lineGeoms << GEOSGeom_clone( splitGeom ); 05337 } 05338 05339 mergeGeometriesMultiTypeSplit( lineGeoms ); 05340 05341 if ( lineGeoms.size() > 0 ) 05342 { 05343 GEOSGeom_destroy( mGeos ); 05344 mGeos = lineGeoms[0]; 05345 mDirtyWkb = true; 05346 } 05347 05348 for ( int i = 1; i < lineGeoms.size(); ++i ) 05349 { 05350 newGeometries << fromGeosGeom( lineGeoms[i] ); 05351 } 05352 05353 GEOSGeom_destroy( splitGeom ); 05354 return 0; 05355 } 05356 05357 int QgsGeometry::splitPolygonGeometry( GEOSGeometry* splitLine, QList<QgsGeometry*>& newGeometries ) 05358 { 05359 if ( !splitLine ) 05360 { 05361 return 2; 05362 } 05363 05364 if ( mDirtyGeos ) 05365 { 05366 exportWkbToGeos(); 05367 } 05368 05369 if ( !mGeos ) 05370 { 05371 return 5; 05372 } 05373 05374 //first test if linestring intersects geometry. If not, return straight away 05375 if ( !GEOSIntersects( splitLine, mGeos ) ) 05376 { 05377 return 1; 05378 } 05379 05380 //first union all the polygon rings together (to get them noded, see JTS developer guide) 05381 GEOSGeometry *nodedGeometry = nodeGeometries( splitLine, mGeos ); 05382 if ( !nodedGeometry ) 05383 { 05384 return 2; //an error occured during noding 05385 } 05386 05387 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \ 05388 ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=1))) 05389 GEOSGeometry *cutEdges = GEOSPolygonizer_getCutEdges( &nodedGeometry, 1 ); 05390 if ( cutEdges ) 05391 { 05392 if ( numberOfGeometries( cutEdges ) > 0 ) 05393 { 05394 GEOSGeom_destroy( cutEdges ); 05395 GEOSGeom_destroy( nodedGeometry ); 05396 return 3; 05397 } 05398 05399 GEOSGeom_destroy( cutEdges ); 05400 } 05401 #endif 05402 05403 GEOSGeometry *polygons = GEOSPolygonize( &nodedGeometry, 1 ); 05404 if ( !polygons || numberOfGeometries( polygons ) == 0 ) 05405 { 05406 if ( polygons ) 05407 GEOSGeom_destroy( polygons ); 05408 05409 GEOSGeom_destroy( nodedGeometry ); 05410 05411 return 4; 05412 } 05413 05414 GEOSGeom_destroy( nodedGeometry ); 05415 05416 //test every polygon if contained in original geometry 05417 //include in result if yes 05418 QVector<GEOSGeometry*> testedGeometries; 05419 GEOSGeometry *intersectGeometry = 0; 05420 05421 //ratio intersect geometry / geometry. This should be close to 1 05422 //if the polygon belongs to the input geometry 05423 05424 for ( int i = 0; i < numberOfGeometries( polygons ); i++ ) 05425 { 05426 const GEOSGeometry *polygon = GEOSGetGeometryN( polygons, i ); 05427 intersectGeometry = GEOSIntersection( mGeos, polygon ); 05428 if ( !intersectGeometry ) 05429 { 05430 QgsDebugMsg( "intersectGeometry is NULL" ); 05431 continue; 05432 } 05433 05434 double intersectionArea; 05435 GEOSArea( intersectGeometry, &intersectionArea ); 05436 05437 double polygonArea; 05438 GEOSArea( polygon, &polygonArea ); 05439 05440 const double areaRatio = intersectionArea / polygonArea; 05441 if ( areaRatio > 0.99 && areaRatio < 1.01 ) 05442 testedGeometries << GEOSGeom_clone( polygon ); 05443 05444 GEOSGeom_destroy( intersectGeometry ); 05445 } 05446 05447 bool splitDone = true; 05448 int nGeometriesThis = numberOfGeometries( mGeos ); //original number of geometries 05449 if ( testedGeometries.size() == nGeometriesThis ) 05450 { 05451 splitDone = false; 05452 } 05453 05454 mergeGeometriesMultiTypeSplit( testedGeometries ); 05455 05456 //no split done, preserve original geometry 05457 if ( !splitDone ) 05458 { 05459 for ( int i = 0; i < testedGeometries.size(); ++i ) 05460 { 05461 GEOSGeom_destroy( testedGeometries[i] ); 05462 } 05463 return 1; 05464 } 05465 else if ( testedGeometries.size() > 0 ) //split successfull 05466 { 05467 GEOSGeom_destroy( mGeos ); 05468 mGeos = testedGeometries[0]; 05469 mDirtyWkb = true; 05470 } 05471 05472 for ( int i = 1; i < testedGeometries.size(); ++i ) 05473 { 05474 newGeometries << fromGeosGeom( testedGeometries[i] ); 05475 } 05476 05477 GEOSGeom_destroy( polygons ); 05478 return 0; 05479 } 05480 05481 GEOSGeometry* QgsGeometry::reshapePolygon( const GEOSGeometry* polygon, const GEOSGeometry* reshapeLineGeos ) 05482 { 05483 //go through outer shell and all inner rings and check if there is exactly one intersection of a ring and the reshape line 05484 int nIntersections = 0; 05485 int lastIntersectingRing = -2; 05486 const GEOSGeometry* lastIntersectingGeom = 0; 05487 05488 int nRings = GEOSGetNumInteriorRings( polygon ); 05489 if ( nRings < 0 ) 05490 { 05491 return 0; 05492 } 05493 05494 //does outer ring intersect? 05495 const GEOSGeometry* outerRing = GEOSGetExteriorRing( polygon ); 05496 if ( GEOSIntersects( outerRing, reshapeLineGeos ) == 1 ) 05497 { 05498 ++nIntersections; 05499 lastIntersectingRing = -1; 05500 lastIntersectingGeom = outerRing; 05501 } 05502 05503 //do inner rings intersect? 05504 const GEOSGeometry **innerRings = new const GEOSGeometry*[nRings]; 05505 05506 try 05507 { 05508 for ( int i = 0; i < nRings; ++i ) 05509 { 05510 innerRings[i] = GEOSGetInteriorRingN( polygon, i ); 05511 if ( GEOSIntersects( innerRings[i], reshapeLineGeos ) == 1 ) 05512 { 05513 ++nIntersections; 05514 lastIntersectingRing = i; 05515 lastIntersectingGeom = innerRings[i]; 05516 } 05517 } 05518 } 05519 catch ( GEOSException &e ) 05520 { 05521 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 05522 nIntersections = 0; 05523 } 05524 05525 if ( nIntersections != 1 ) //reshape line is only allowed to intersect one ring 05526 { 05527 delete [] innerRings; 05528 return 0; 05529 } 05530 05531 //we have one intersecting ring, let's try to reshape it 05532 GEOSGeometry* reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos ); 05533 if ( !reshapeResult ) 05534 { 05535 delete [] innerRings; 05536 return 0; 05537 } 05538 05539 //if reshaping took place, we need to reassemble the polygon and its rings 05540 GEOSGeometry* newRing = 0; 05541 const GEOSCoordSequence* reshapeSequence = GEOSGeom_getCoordSeq( reshapeResult ); 05542 GEOSCoordSequence* newCoordSequence = GEOSCoordSeq_clone( reshapeSequence ); 05543 05544 GEOSGeom_destroy( reshapeResult ); 05545 05546 newRing = GEOSGeom_createLinearRing( newCoordSequence ); 05547 if ( !newRing ) 05548 { 05549 delete [] innerRings; 05550 return 0; 05551 } 05552 05553 05554 GEOSGeometry* newOuterRing = 0; 05555 if ( lastIntersectingRing == -1 ) 05556 { 05557 newOuterRing = newRing; 05558 } 05559 else 05560 { 05561 newOuterRing = GEOSGeom_clone( outerRing ); 05562 } 05563 05564 //check if all the rings are still inside the outer boundary 05565 QList<GEOSGeometry*> ringList; 05566 if ( nRings > 0 ) 05567 { 05568 GEOSGeometry* outerRingPoly = GEOSGeom_createPolygon( GEOSGeom_clone( newOuterRing ), 0, 0 ); 05569 if ( outerRingPoly ) 05570 { 05571 GEOSGeometry* currentRing = 0; 05572 for ( int i = 0; i < nRings; ++i ) 05573 { 05574 if ( lastIntersectingRing == i ) 05575 { 05576 currentRing = newRing; 05577 } 05578 else 05579 { 05580 currentRing = GEOSGeom_clone( innerRings[i] ); 05581 } 05582 05583 //possibly a ring is no longer contained in the result polygon after reshape 05584 if ( GEOSContains( outerRingPoly, currentRing ) == 1 ) 05585 { 05586 ringList.push_back( currentRing ); 05587 } 05588 else 05589 { 05590 GEOSGeom_destroy( currentRing ); 05591 } 05592 } 05593 } 05594 GEOSGeom_destroy( outerRingPoly ); 05595 } 05596 05597 GEOSGeometry** newInnerRings = new GEOSGeometry*[ringList.size()]; 05598 for ( int i = 0; i < ringList.size(); ++i ) 05599 { 05600 newInnerRings[i] = ringList.at( i ); 05601 } 05602 05603 delete [] innerRings; 05604 05605 GEOSGeometry* reshapedPolygon = GEOSGeom_createPolygon( newOuterRing, newInnerRings, ringList.size() ); 05606 delete[] newInnerRings; 05607 if ( !reshapedPolygon ) 05608 { 05609 return 0; 05610 } 05611 return reshapedPolygon; 05612 } 05613 05614 GEOSGeometry* QgsGeometry::reshapeLine( const GEOSGeometry* line, const GEOSGeometry* reshapeLineGeos ) 05615 { 05616 if ( !line || !reshapeLineGeos ) 05617 { 05618 return 0; 05619 } 05620 05621 bool atLeastTwoIntersections = false; 05622 05623 try 05624 { 05625 //make sure there are at least two intersection between line and reshape geometry 05626 GEOSGeometry* intersectGeom = GEOSIntersection( line, reshapeLineGeos ); 05627 if ( intersectGeom ) 05628 { 05629 atLeastTwoIntersections = ( GEOSGeomTypeId( intersectGeom ) == GEOS_MULTIPOINT && GEOSGetNumGeometries( intersectGeom ) > 1 ); 05630 GEOSGeom_destroy( intersectGeom ); 05631 } 05632 } 05633 catch ( GEOSException &e ) 05634 { 05635 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 05636 atLeastTwoIntersections = false; 05637 } 05638 05639 if ( !atLeastTwoIntersections ) 05640 { 05641 return 0; 05642 } 05643 05644 //begin and end point of original line 05645 const GEOSCoordSequence* lineCoordSeq = GEOSGeom_getCoordSeq( line ); 05646 if ( !lineCoordSeq ) 05647 { 05648 return 0; 05649 } 05650 unsigned int lineCoordSeqSize; 05651 if ( GEOSCoordSeq_getSize( lineCoordSeq, &lineCoordSeqSize ) == 0 ) 05652 { 05653 return 0; 05654 } 05655 if ( lineCoordSeqSize < 2 ) 05656 { 05657 return 0; 05658 } 05659 //first and last vertex of line 05660 double x1, y1, x2, y2; 05661 GEOSCoordSeq_getX( lineCoordSeq, 0, &x1 ); 05662 GEOSCoordSeq_getY( lineCoordSeq, 0, &y1 ); 05663 GEOSCoordSeq_getX( lineCoordSeq, lineCoordSeqSize - 1, &x2 ); 05664 GEOSCoordSeq_getY( lineCoordSeq, lineCoordSeqSize - 1, &y2 ); 05665 GEOSGeometry* beginLineVertex = createGeosPoint( QgsPoint( x1, y1 ) ); 05666 GEOSGeometry* endLineVertex = createGeosPoint( QgsPoint( x2, y2 ) ); 05667 05668 bool isRing = false; 05669 if ( GEOSGeomTypeId( line ) == GEOS_LINEARRING || GEOSEquals( beginLineVertex, endLineVertex ) == 1 ) 05670 { 05671 isRing = true; 05672 } 05673 05674 //node line and reshape line 05675 GEOSGeometry* nodedGeometry = nodeGeometries( reshapeLineGeos, line ); 05676 if ( !nodedGeometry ) 05677 { 05678 GEOSGeom_destroy( beginLineVertex ); 05679 GEOSGeom_destroy( endLineVertex ); 05680 return 0; 05681 } 05682 05683 //and merge them together 05684 GEOSGeometry *mergedLines = GEOSLineMerge( nodedGeometry ); 05685 GEOSGeom_destroy( nodedGeometry ); 05686 if ( !mergedLines ) 05687 { 05688 GEOSGeom_destroy( beginLineVertex ); 05689 GEOSGeom_destroy( endLineVertex ); 05690 return 0; 05691 } 05692 05693 int numMergedLines = GEOSGetNumGeometries( mergedLines ); 05694 if ( numMergedLines < 2 ) //some special cases. Normally it is >2 05695 { 05696 GEOSGeom_destroy( beginLineVertex ); 05697 GEOSGeom_destroy( endLineVertex ); 05698 if ( numMergedLines == 1 ) //reshape line is from begin to endpoint. So we keep the reshapeline 05699 { 05700 return GEOSGeom_clone( reshapeLineGeos ); 05701 } 05702 else 05703 { 05704 return 0; 05705 } 05706 } 05707 05708 QList<GEOSGeometry*> resultLineParts; //collection with the line segments that will be contained in result 05709 QList<GEOSGeometry*> probableParts; //parts where we can decide on inclusion only after going through all the candidates 05710 05711 for ( int i = 0; i < numMergedLines; ++i ) 05712 { 05713 const GEOSGeometry* currentGeom; 05714 05715 currentGeom = GEOSGetGeometryN( mergedLines, i ); 05716 const GEOSCoordSequence* currentCoordSeq = GEOSGeom_getCoordSeq( currentGeom ); 05717 unsigned int currentCoordSeqSize; 05718 GEOSCoordSeq_getSize( currentCoordSeq, ¤tCoordSeqSize ); 05719 if ( currentCoordSeqSize < 2 ) 05720 { 05721 continue; 05722 } 05723 05724 //get the two endpoints of the current line merge result 05725 double xBegin, xEnd, yBegin, yEnd; 05726 GEOSCoordSeq_getX( currentCoordSeq, 0, &xBegin ); 05727 GEOSCoordSeq_getY( currentCoordSeq, 0, &yBegin ); 05728 GEOSCoordSeq_getX( currentCoordSeq, currentCoordSeqSize - 1, &xEnd ); 05729 GEOSCoordSeq_getY( currentCoordSeq, currentCoordSeqSize - 1, &yEnd ); 05730 GEOSGeometry* beginCurrentGeomVertex = createGeosPoint( QgsPoint( xBegin, yBegin ) ); 05731 GEOSGeometry* endCurrentGeomVertex = createGeosPoint( QgsPoint( xEnd, yEnd ) ); 05732 05733 //check how many endpoints of the line merge result are on the (original) line 05734 int nEndpointsOnOriginalLine = 0; 05735 if ( pointContainedInLine( beginCurrentGeomVertex, line ) == 1 ) 05736 { 05737 nEndpointsOnOriginalLine += 1; 05738 } 05739 05740 if ( pointContainedInLine( endCurrentGeomVertex, line ) == 1 ) 05741 { 05742 nEndpointsOnOriginalLine += 1; 05743 } 05744 05745 //check how many endpoints equal the endpoints of the original line 05746 int nEndpointsSameAsOriginalLine = 0; 05747 if ( GEOSEquals( beginCurrentGeomVertex, beginLineVertex ) == 1 || GEOSEquals( beginCurrentGeomVertex, endLineVertex ) == 1 ) 05748 { 05749 nEndpointsSameAsOriginalLine += 1; 05750 } 05751 if ( GEOSEquals( endCurrentGeomVertex, beginLineVertex ) == 1 || GEOSEquals( endCurrentGeomVertex, endLineVertex ) == 1 ) 05752 { 05753 nEndpointsSameAsOriginalLine += 1; 05754 } 05755 05756 //check if the current geometry overlaps the original geometry (GEOSOverlap does not seem to work with linestrings) 05757 bool currentGeomOverlapsOriginalGeom = false; 05758 bool currentGeomOverlapsReshapeLine = false; 05759 if ( QgsGeometry::lineContainedInLine( currentGeom, line ) == 1 ) 05760 { 05761 currentGeomOverlapsOriginalGeom = true; 05762 } 05763 if ( QgsGeometry::lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 ) 05764 { 05765 currentGeomOverlapsReshapeLine = true; 05766 } 05767 05768 05769 //logic to decide if this part belongs to the result 05770 if ( nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom ) 05771 { 05772 resultLineParts.push_back( GEOSGeom_clone( currentGeom ) ); 05773 } 05774 //for closed rings, we take one segment from the candidate list 05775 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom ) 05776 { 05777 probableParts.push_back( GEOSGeom_clone( currentGeom ) ); 05778 } 05779 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom ) 05780 { 05781 resultLineParts.push_back( GEOSGeom_clone( currentGeom ) ); 05782 } 05783 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom ) 05784 { 05785 resultLineParts.push_back( GEOSGeom_clone( currentGeom ) ); 05786 } 05787 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine ) 05788 { 05789 resultLineParts.push_back( GEOSGeom_clone( currentGeom ) ); 05790 } 05791 05792 GEOSGeom_destroy( beginCurrentGeomVertex ); 05793 GEOSGeom_destroy( endCurrentGeomVertex ); 05794 } 05795 05796 //add the longest segment from the probable list for rings (only used for polygon rings) 05797 if ( isRing && probableParts.size() > 0 ) 05798 { 05799 GEOSGeometry* maxGeom = 0; //the longest geometry in the probabla list 05800 GEOSGeometry* currentGeom = 0; 05801 double maxLength = -DBL_MAX; 05802 double currentLength = 0; 05803 for ( int i = 0; i < probableParts.size(); ++i ) 05804 { 05805 currentGeom = probableParts.at( i ); 05806 GEOSLength( currentGeom, ¤tLength ); 05807 if ( currentLength > maxLength ) 05808 { 05809 maxLength = currentLength; 05810 GEOSGeom_destroy( maxGeom ); 05811 maxGeom = currentGeom; 05812 } 05813 else 05814 { 05815 GEOSGeom_destroy( currentGeom ); 05816 } 05817 } 05818 resultLineParts.push_back( maxGeom ); 05819 } 05820 05821 GEOSGeom_destroy( beginLineVertex ); 05822 GEOSGeom_destroy( endLineVertex ); 05823 GEOSGeom_destroy( mergedLines ); 05824 05825 GEOSGeometry* result = 0; 05826 if ( resultLineParts.size() < 1 ) 05827 { 05828 return 0; 05829 } 05830 if ( resultLineParts.size() == 1 ) //the whole result was reshaped 05831 { 05832 result = resultLineParts[0]; 05833 } 05834 else //>1 05835 { 05836 GEOSGeometry **lineArray = new GEOSGeometry*[resultLineParts.size()]; 05837 for ( int i = 0; i < resultLineParts.size(); ++i ) 05838 { 05839 lineArray[i] = resultLineParts[i]; 05840 } 05841 05842 //create multiline from resultLineParts 05843 GEOSGeometry* multiLineGeom = GEOSGeom_createCollection( GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ); 05844 delete [] lineArray; 05845 05846 //then do a linemerge with the newly combined partstrings 05847 result = GEOSLineMerge( multiLineGeom ); 05848 GEOSGeom_destroy( multiLineGeom ); 05849 } 05850 05851 //now test if the result is a linestring. Otherwise something went wrong 05852 if ( GEOSGeomTypeId( result ) != GEOS_LINESTRING ) 05853 { 05854 GEOSGeom_destroy( result ); 05855 return 0; 05856 } 05857 return result; 05858 } 05859 05860 int QgsGeometry::topologicalTestPointsSplit( const GEOSGeometry* splitLine, QList<QgsPoint>& testPoints ) const 05861 { 05862 //Find out the intersection points between splitLineGeos and this geometry. 05863 //These points need to be tested for topological correctness by the calling function 05864 //if topological editing is enabled 05865 05866 testPoints.clear(); 05867 GEOSGeometry* intersectionGeom = GEOSIntersection( mGeos, splitLine ); 05868 if ( !intersectionGeom ) 05869 { 05870 return 1; 05871 } 05872 05873 bool simple = false; 05874 int nIntersectGeoms = 1; 05875 if ( GEOSGeomTypeId( intersectionGeom ) == GEOS_LINESTRING || GEOSGeomTypeId( intersectionGeom ) == GEOS_POINT ) 05876 { 05877 simple = true; 05878 } 05879 05880 if ( !simple ) 05881 { 05882 nIntersectGeoms = GEOSGetNumGeometries( intersectionGeom ); 05883 } 05884 05885 for ( int i = 0; i < nIntersectGeoms; ++i ) 05886 { 05887 const GEOSGeometry* currentIntersectGeom; 05888 if ( simple ) 05889 { 05890 currentIntersectGeom = intersectionGeom; 05891 } 05892 else 05893 { 05894 currentIntersectGeom = GEOSGetGeometryN( intersectionGeom, i ); 05895 } 05896 05897 const GEOSCoordSequence* lineSequence = GEOSGeom_getCoordSeq( currentIntersectGeom ); 05898 unsigned int sequenceSize = 0; 05899 double x, y; 05900 if ( GEOSCoordSeq_getSize( lineSequence, &sequenceSize ) != 0 ) 05901 { 05902 for ( unsigned int i = 0; i < sequenceSize; ++i ) 05903 { 05904 if ( GEOSCoordSeq_getX( lineSequence, i, &x ) != 0 ) 05905 { 05906 if ( GEOSCoordSeq_getY( lineSequence, i, &y ) != 0 ) 05907 { 05908 testPoints.push_back( QgsPoint( x, y ) ); 05909 } 05910 } 05911 } 05912 } 05913 } 05914 GEOSGeom_destroy( intersectionGeom ); 05915 return 0; 05916 } 05917 05918 GEOSGeometry *QgsGeometry::nodeGeometries( const GEOSGeometry *splitLine, const GEOSGeometry *geom ) 05919 { 05920 if ( !splitLine || !geom ) 05921 { 05922 return 0; 05923 } 05924 05925 GEOSGeometry *geometryBoundary = 0; 05926 if ( GEOSGeomTypeId( geom ) == GEOS_POLYGON || GEOSGeomTypeId( geom ) == GEOS_MULTIPOLYGON ) 05927 { 05928 geometryBoundary = GEOSBoundary( geom ); 05929 } 05930 else 05931 { 05932 geometryBoundary = GEOSGeom_clone( geom ); 05933 } 05934 05935 GEOSGeometry *splitLineClone = GEOSGeom_clone( splitLine ); 05936 GEOSGeometry *unionGeometry = GEOSUnion( splitLineClone, geometryBoundary ); 05937 GEOSGeom_destroy( splitLineClone ); 05938 05939 GEOSGeom_destroy( geometryBoundary ); 05940 return unionGeometry; 05941 } 05942 05943 int QgsGeometry::lineContainedInLine( const GEOSGeometry* line1, const GEOSGeometry* line2 ) 05944 { 05945 if ( !line1 || !line2 ) 05946 { 05947 return -1; 05948 } 05949 05950 05951 double bufferDistance = 0.00001; 05952 if ( geomInDegrees( line2 ) ) //use more accurate tolerance for degrees 05953 { 05954 bufferDistance = 0.00000001; 05955 } 05956 GEOSGeometry* bufferGeom = GEOSBuffer( line2, bufferDistance, DEFAULT_QUADRANT_SEGMENTS ); 05957 if ( !bufferGeom ) 05958 { 05959 return -2; 05960 } 05961 05962 GEOSGeometry* intersectionGeom = GEOSIntersection( bufferGeom, line1 ); 05963 05964 //compare ratio between line1Length and intersectGeomLength (usually close to 1 if line1 is contained in line2) 05965 double intersectGeomLength; 05966 double line1Length; 05967 05968 GEOSLength( intersectionGeom, &intersectGeomLength ); 05969 GEOSLength( line1, &line1Length ); 05970 05971 GEOSGeom_destroy( bufferGeom ); 05972 GEOSGeom_destroy( intersectionGeom ); 05973 05974 double intersectRatio = line1Length / intersectGeomLength; 05975 if ( intersectRatio > 0.9 && intersectRatio < 1.1 ) 05976 { 05977 return 1; 05978 } 05979 return 0; 05980 } 05981 05982 int QgsGeometry::pointContainedInLine( const GEOSGeometry* point, const GEOSGeometry* line ) 05983 { 05984 if ( !point || !line ) 05985 { 05986 return -1; 05987 } 05988 05989 double bufferDistance = 0.000001; 05990 if ( geomInDegrees( line ) ) 05991 { 05992 bufferDistance = 0.00000001; 05993 } 05994 GEOSGeometry* lineBuffer = GEOSBuffer( line, bufferDistance, 8 ); 05995 if ( !lineBuffer ) 05996 { 05997 return -2; 05998 } 05999 06000 bool contained = false; 06001 if ( GEOSContains( lineBuffer, point ) == 1 ) 06002 { 06003 contained = true; 06004 } 06005 06006 GEOSGeom_destroy( lineBuffer ); 06007 return contained; 06008 } 06009 06010 bool QgsGeometry::geomInDegrees( const GEOSGeometry* geom ) 06011 { 06012 GEOSGeometry* bbox = GEOSEnvelope( geom ); 06013 if ( !bbox ) 06014 { 06015 return false; 06016 } 06017 06018 const GEOSGeometry* bBoxRing = GEOSGetExteriorRing( bbox ); 06019 if ( !bBoxRing ) 06020 { 06021 return false; 06022 } 06023 const GEOSCoordSequence* bBoxCoordSeq = GEOSGeom_getCoordSeq( bBoxRing ); 06024 06025 if ( !bBoxCoordSeq ) 06026 { 06027 return false; 06028 } 06029 06030 unsigned int nCoords = 0; 06031 if ( !GEOSCoordSeq_getSize( bBoxCoordSeq, &nCoords ) ) 06032 { 06033 return false; 06034 } 06035 06036 double x, y; 06037 for ( unsigned int i = 0; i < ( nCoords - 1 ); ++i ) 06038 { 06039 GEOSCoordSeq_getX( bBoxCoordSeq, i, &x ); 06040 if ( x > 180 || x < -180 ) 06041 { 06042 return false; 06043 } 06044 GEOSCoordSeq_getY( bBoxCoordSeq, i, &y ); 06045 if ( y > 90 || y < -90 ) 06046 { 06047 return false; 06048 } 06049 } 06050 06051 return true; 06052 } 06053 06054 int QgsGeometry::numberOfGeometries( GEOSGeometry* g ) const 06055 { 06056 if ( !g ) 06057 { 06058 return 0; 06059 } 06060 int geometryType = GEOSGeomTypeId( g ); 06061 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING 06062 || geometryType == GEOS_POLYGON ) 06063 { 06064 return 1; 06065 } 06066 06067 //calling GEOSGetNumGeometries is save for multi types and collections also in geos2 06068 return GEOSGetNumGeometries( g ); 06069 } 06070 06071 int QgsGeometry::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry*>& splitResult ) 06072 { 06073 if ( mDirtyGeos ) 06074 { 06075 exportWkbToGeos(); 06076 } 06077 06078 if ( !mGeos ) 06079 { 06080 return 1; 06081 } 06082 06083 //convert mGeos to geometry collection 06084 int type = GEOSGeomTypeId( mGeos ); 06085 if ( type != GEOS_GEOMETRYCOLLECTION && 06086 type != GEOS_MULTILINESTRING && 06087 type != GEOS_MULTIPOLYGON && 06088 type != GEOS_MULTIPOINT ) 06089 { 06090 return 0; 06091 } 06092 06093 QVector<GEOSGeometry*> copyList = splitResult; 06094 splitResult.clear(); 06095 06096 //collect all the geometries that belong to the initial multifeature 06097 QVector<GEOSGeometry*> unionGeom; 06098 06099 for ( int i = 0; i < copyList.size(); ++i ) 06100 { 06101 //is this geometry a part of the original multitype? 06102 bool isPart = false; 06103 for ( int j = 0; j < GEOSGetNumGeometries( mGeos ); j++ ) 06104 { 06105 if ( GEOSEquals( copyList[i], GEOSGetGeometryN( mGeos, j ) ) ) 06106 { 06107 isPart = true; 06108 break; 06109 } 06110 } 06111 06112 if ( isPart ) 06113 { 06114 unionGeom << copyList[i]; 06115 } 06116 else 06117 { 06118 QVector<GEOSGeometry*> geomVector; 06119 geomVector << copyList[i]; 06120 06121 if ( type == GEOS_MULTILINESTRING ) 06122 { 06123 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ); 06124 } 06125 else if ( type == GEOS_MULTIPOLYGON ) 06126 { 06127 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ); 06128 } 06129 else 06130 { 06131 GEOSGeom_destroy( copyList[i] ); 06132 } 06133 } 06134 } 06135 06136 //make multifeature out of unionGeom 06137 if ( unionGeom.size() > 0 ) 06138 { 06139 if ( type == GEOS_MULTILINESTRING ) 06140 { 06141 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ); 06142 } 06143 else if ( type == GEOS_MULTIPOLYGON ) 06144 { 06145 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ); 06146 } 06147 } 06148 else 06149 { 06150 unionGeom.clear(); 06151 } 06152 06153 return 0; 06154 } 06155 06156 QgsPoint QgsGeometry::asPoint( unsigned char*& ptr, bool hasZValue ) 06157 { 06158 ptr += 5; 06159 double* x = ( double * )( ptr ); 06160 double* y = ( double * )( ptr + sizeof( double ) ); 06161 ptr += 2 * sizeof( double ); 06162 06163 if ( hasZValue ) 06164 ptr += sizeof( double ); 06165 06166 return QgsPoint( *x, *y ); 06167 } 06168 06169 06170 QgsPolyline QgsGeometry::asPolyline( unsigned char*& ptr, bool hasZValue ) 06171 { 06172 double x, y; 06173 ptr += 5; 06174 unsigned int nPoints = *(( int* )ptr ); 06175 ptr += 4; 06176 06177 QgsPolyline line( nPoints ); 06178 06179 // Extract the points from the WKB format into the x and y vectors. 06180 for ( uint i = 0; i < nPoints; ++i ) 06181 { 06182 x = *(( double * ) ptr ); 06183 y = *(( double * )( ptr + sizeof( double ) ) ); 06184 06185 ptr += 2 * sizeof( double ); 06186 06187 line[i] = QgsPoint( x, y ); 06188 06189 if ( hasZValue ) // ignore Z value 06190 ptr += sizeof( double ); 06191 } 06192 06193 return line; 06194 } 06195 06196 06197 QgsPolygon QgsGeometry::asPolygon( unsigned char*& ptr, bool hasZValue ) 06198 { 06199 double x, y; 06200 06201 ptr += 5; 06202 06203 // get number of rings in the polygon 06204 unsigned int numRings = *(( int* )ptr ); 06205 ptr += 4; 06206 06207 if ( numRings == 0 ) // sanity check for zero rings in polygon 06208 return QgsPolygon(); 06209 06210 QgsPolygon rings( numRings ); 06211 06212 for ( uint idx = 0; idx < numRings; idx++ ) 06213 { 06214 uint nPoints = *(( int* )ptr ); 06215 ptr += 4; 06216 06217 QgsPolyline ring( nPoints ); 06218 06219 for ( uint jdx = 0; jdx < nPoints; jdx++ ) 06220 { 06221 x = *(( double * ) ptr ); 06222 y = *(( double * )( ptr + sizeof( double ) ) ); 06223 06224 ptr += 2 * sizeof( double ); 06225 06226 if ( hasZValue ) 06227 ptr += sizeof( double ); 06228 06229 ring[jdx] = QgsPoint( x, y ); 06230 } 06231 06232 rings[idx] = ring; 06233 } 06234 06235 return rings; 06236 } 06237 06238 06239 QgsPoint QgsGeometry::asPoint() 06240 { 06241 QGis::WkbType type = wkbType(); 06242 if ( type != QGis::WKBPoint && type != QGis::WKBPoint25D ) 06243 return QgsPoint( 0, 0 ); 06244 06245 unsigned char* ptr = mGeometry; 06246 return asPoint( ptr, type == QGis::WKBPoint25D ); 06247 } 06248 06249 QgsPolyline QgsGeometry::asPolyline() 06250 { 06251 QGis::WkbType type = wkbType(); 06252 if ( type != QGis::WKBLineString && type != QGis::WKBLineString25D ) 06253 return QgsPolyline(); 06254 06255 unsigned char *ptr = mGeometry; 06256 return asPolyline( ptr, type == QGis::WKBLineString25D ); 06257 } 06258 06259 QgsPolygon QgsGeometry::asPolygon() 06260 { 06261 QGis::WkbType type = wkbType(); 06262 if ( type != QGis::WKBPolygon && type != QGis::WKBPolygon25D ) 06263 return QgsPolygon(); 06264 06265 unsigned char *ptr = mGeometry; 06266 return asPolygon( ptr, type == QGis::WKBPolygon25D ); 06267 } 06268 06269 QgsMultiPoint QgsGeometry::asMultiPoint() 06270 { 06271 QGis::WkbType type = wkbType(); 06272 if ( type != QGis::WKBMultiPoint && type != QGis::WKBMultiPoint25D ) 06273 return QgsMultiPoint(); 06274 06275 bool hasZValue = ( type == QGis::WKBMultiPoint25D ); 06276 06277 unsigned char* ptr = mGeometry + 5; 06278 unsigned int nPoints = *(( int* )ptr ); 06279 ptr += 4; 06280 06281 QgsMultiPoint points( nPoints ); 06282 for ( uint i = 0; i < nPoints; i++ ) 06283 { 06284 points[i] = asPoint( ptr, hasZValue ); 06285 } 06286 06287 return points; 06288 } 06289 06290 QgsMultiPolyline QgsGeometry::asMultiPolyline() 06291 { 06292 QGis::WkbType type = wkbType(); 06293 if ( type != QGis::WKBMultiLineString && type != QGis::WKBMultiLineString25D ) 06294 return QgsMultiPolyline(); 06295 06296 bool hasZValue = ( type == QGis::WKBMultiLineString25D ); 06297 06298 unsigned char* ptr = mGeometry + 5; 06299 unsigned int numLineStrings = *(( int* )ptr ); 06300 ptr += 4; 06301 06302 QgsMultiPolyline lines( numLineStrings ); 06303 06304 for ( uint i = 0; i < numLineStrings; i++ ) 06305 { 06306 lines[i] = asPolyline( ptr, hasZValue ); 06307 } 06308 06309 return lines; 06310 } 06311 06312 QgsMultiPolygon QgsGeometry::asMultiPolygon() 06313 { 06314 QGis::WkbType type = wkbType(); 06315 if ( type != QGis::WKBMultiPolygon && type != QGis::WKBMultiPolygon25D ) 06316 return QgsMultiPolygon(); 06317 06318 bool hasZValue = ( type == QGis::WKBMultiPolygon25D ); 06319 06320 unsigned char* ptr = mGeometry + 5; 06321 unsigned int numPolygons = *(( int* )ptr ); 06322 ptr += 4; 06323 06324 QgsMultiPolygon polygons( numPolygons ); 06325 06326 for ( uint i = 0; i < numPolygons; i++ ) 06327 { 06328 polygons[i] = asPolygon( ptr, hasZValue ); 06329 } 06330 06331 return polygons; 06332 } 06333 06334 double QgsGeometry::area() 06335 { 06336 if ( mDirtyGeos ) 06337 { 06338 exportWkbToGeos(); 06339 } 06340 if ( !mGeos ) 06341 { 06342 return -1.0; 06343 } 06344 06345 double area; 06346 06347 try 06348 { 06349 if ( GEOSArea( mGeos, &area ) == 0 ) 06350 return -1.0; 06351 } 06352 CATCH_GEOS( -1.0 ) 06353 06354 return area; 06355 } 06356 06357 double QgsGeometry::length() 06358 { 06359 if ( mDirtyGeos ) 06360 { 06361 exportWkbToGeos(); 06362 } 06363 if ( !mGeos ) 06364 { 06365 return -1.0; 06366 } 06367 06368 double length; 06369 06370 try 06371 { 06372 if ( GEOSLength( mGeos, &length ) == 0 ) 06373 return -1.0; 06374 } 06375 CATCH_GEOS( -1.0 ) 06376 06377 return length; 06378 } 06379 double QgsGeometry::distance( QgsGeometry& geom ) 06380 { 06381 if ( mDirtyGeos ) 06382 { 06383 exportWkbToGeos(); 06384 } 06385 if ( geom.mDirtyGeos ) 06386 { 06387 geom.exportWkbToGeos(); 06388 } 06389 06390 if ( !mGeos || !geom.mGeos ) 06391 return -1.0; 06392 06393 double dist = -1.0; 06394 06395 try 06396 { 06397 GEOSDistance( mGeos, geom.mGeos, &dist ); 06398 } 06399 CATCH_GEOS( -1.0 ) 06400 06401 return dist; 06402 } 06403 06404 06405 QgsGeometry* QgsGeometry::buffer( double distance, int segments ) 06406 { 06407 if ( mDirtyGeos ) 06408 { 06409 exportWkbToGeos(); 06410 } 06411 if ( !mGeos ) 06412 { 06413 return 0; 06414 } 06415 06416 try 06417 { 06418 return fromGeosGeom( GEOSBuffer( mGeos, distance, segments ) ); 06419 } 06420 CATCH_GEOS( 0 ) 06421 } 06422 06423 QgsGeometry* QgsGeometry::simplify( double tolerance ) 06424 { 06425 if ( mDirtyGeos ) 06426 { 06427 exportWkbToGeos(); 06428 } 06429 if ( !mGeos ) 06430 { 06431 return 0; 06432 } 06433 try 06434 { 06435 return fromGeosGeom( GEOSSimplify( mGeos, tolerance ) ); 06436 } 06437 CATCH_GEOS( 0 ) 06438 } 06439 06440 QgsGeometry* QgsGeometry::centroid() 06441 { 06442 if ( mDirtyGeos ) 06443 { 06444 exportWkbToGeos(); 06445 } 06446 if ( !mGeos ) 06447 { 06448 return 0; 06449 } 06450 try 06451 { 06452 return fromGeosGeom( GEOSGetCentroid( mGeos ) ); 06453 } 06454 CATCH_GEOS( 0 ) 06455 } 06456 06457 QgsGeometry* QgsGeometry::convexHull() 06458 { 06459 if ( mDirtyGeos ) 06460 { 06461 exportWkbToGeos(); 06462 } 06463 if ( !mGeos ) 06464 { 06465 return 0; 06466 } 06467 06468 try 06469 { 06470 return fromGeosGeom( GEOSConvexHull( mGeos ) ); 06471 } 06472 CATCH_GEOS( 0 ) 06473 } 06474 06475 QgsGeometry* QgsGeometry::interpolate( double distance ) 06476 { 06477 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \ 06478 ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=2))) 06479 if ( mDirtyGeos ) 06480 { 06481 exportWkbToGeos(); 06482 } 06483 if ( !mGeos ) 06484 { 06485 return 0; 06486 } 06487 06488 try 06489 { 06490 return fromGeosGeom( GEOSInterpolate( mGeos, distance ) ); 06491 } 06492 CATCH_GEOS( 0 ) 06493 #else 06494 QgsMessageLog::logMessage( QObject::tr( "GEOS prior to 3.2 doesn't support GEOSInterpolate" ), QObject::tr( "GEOS" ) ); 06495 #endif 06496 } 06497 06498 QgsGeometry* QgsGeometry::intersection( QgsGeometry* geometry ) 06499 { 06500 if ( !geometry ) 06501 { 06502 return NULL; 06503 } 06504 06505 if ( mDirtyGeos ) 06506 { 06507 exportWkbToGeos(); 06508 } 06509 if ( geometry->mDirtyGeos ) 06510 { 06511 geometry->exportWkbToGeos(); 06512 } 06513 06514 06515 if ( !mGeos || !geometry->mGeos ) 06516 { 06517 return 0; 06518 } 06519 06520 try 06521 { 06522 return fromGeosGeom( GEOSIntersection( mGeos, geometry->mGeos ) ); 06523 } 06524 CATCH_GEOS( 0 ) 06525 } 06526 06527 QgsGeometry* QgsGeometry::combine( QgsGeometry* geometry ) 06528 { 06529 if ( !geometry ) 06530 { 06531 return NULL; 06532 } 06533 06534 if ( mDirtyGeos ) 06535 { 06536 exportWkbToGeos(); 06537 } 06538 if ( geometry->mDirtyGeos ) 06539 { 06540 geometry->exportWkbToGeos(); 06541 } 06542 06543 if ( !mGeos || !geometry->mGeos ) 06544 { 06545 return 0; 06546 } 06547 06548 try 06549 { 06550 GEOSGeometry* unionGeom = GEOSUnion( mGeos, geometry->mGeos ); 06551 if ( type() == QGis::Line ) 06552 { 06553 GEOSGeometry* mergedGeom = GEOSLineMerge( unionGeom ); 06554 if ( mergedGeom ) 06555 { 06556 GEOSGeom_destroy( unionGeom ); 06557 unionGeom = mergedGeom; 06558 } 06559 } 06560 return fromGeosGeom( unionGeom ); 06561 } 06562 CATCH_GEOS( new QgsGeometry( *this ) ) //return this geometry if union not possible 06563 } 06564 06565 QgsGeometry* QgsGeometry::difference( QgsGeometry* geometry ) 06566 { 06567 if ( !geometry ) 06568 { 06569 return NULL; 06570 } 06571 06572 if ( mDirtyGeos ) 06573 { 06574 exportWkbToGeos(); 06575 } 06576 if ( geometry->mDirtyGeos ) 06577 { 06578 geometry->exportWkbToGeos(); 06579 } 06580 06581 if ( !mGeos || !geometry->mGeos ) 06582 { 06583 return 0; 06584 } 06585 06586 try 06587 { 06588 return fromGeosGeom( GEOSDifference( mGeos, geometry->mGeos ) ); 06589 } 06590 CATCH_GEOS( 0 ) 06591 } 06592 06593 QgsGeometry* QgsGeometry::symDifference( QgsGeometry* geometry ) 06594 { 06595 if ( !geometry ) 06596 { 06597 return NULL; 06598 } 06599 06600 if ( mDirtyGeos ) 06601 { 06602 exportWkbToGeos(); 06603 } 06604 if ( geometry->mDirtyGeos ) 06605 { 06606 geometry->exportWkbToGeos(); 06607 } 06608 06609 if ( !mGeos || !geometry->mGeos ) 06610 { 06611 return 0; 06612 } 06613 06614 try 06615 { 06616 return fromGeosGeom( GEOSSymDifference( mGeos, geometry->mGeos ) ); 06617 } 06618 CATCH_GEOS( 0 ) 06619 } 06620 06621 QList<QgsGeometry*> QgsGeometry::asGeometryCollection() 06622 { 06623 if ( mDirtyGeos ) 06624 { 06625 exportWkbToGeos(); 06626 } 06627 06628 if ( !mGeos ) 06629 { 06630 return QList<QgsGeometry*>(); 06631 } 06632 06633 int type = GEOSGeomTypeId( mGeos ); 06634 QgsDebugMsg( "geom type: " + QString::number( type ) ); 06635 06636 QList<QgsGeometry*> geomCollection; 06637 06638 if ( type != GEOS_MULTIPOINT && 06639 type != GEOS_MULTILINESTRING && 06640 type != GEOS_MULTIPOLYGON && 06641 type != GEOS_GEOMETRYCOLLECTION ) 06642 { 06643 // we have a single-part geometry - put there a copy of this one 06644 geomCollection.append( new QgsGeometry( *this ) ); 06645 return geomCollection; 06646 } 06647 06648 int count = GEOSGetNumGeometries( mGeos ); 06649 QgsDebugMsg( "geom count: " + QString::number( count ) ); 06650 06651 for ( int i = 0; i < count; ++i ) 06652 { 06653 const GEOSGeometry * geometry = GEOSGetGeometryN( mGeos, i ); 06654 geomCollection.append( fromGeosGeom( GEOSGeom_clone( geometry ) ) ); 06655 } 06656 06657 return geomCollection; 06658 } 06659 06660 06661 bool QgsGeometry::deleteRing( int ringNum, int partNum ) 06662 { 06663 if ( ringNum <= 0 || partNum < 0 ) 06664 return false; 06665 06666 switch ( wkbType() ) 06667 { 06668 case QGis::WKBPolygon25D: 06669 case QGis::WKBPolygon: 06670 { 06671 if ( partNum != 0 ) 06672 return false; 06673 06674 QgsPolygon polygon = asPolygon(); 06675 if ( ringNum >= polygon.count() ) 06676 return false; 06677 06678 polygon.remove( ringNum ); 06679 06680 QgsGeometry* g2 = QgsGeometry::fromPolygon( polygon ); 06681 *this = *g2; 06682 delete g2; 06683 return true; 06684 } 06685 06686 case QGis::WKBMultiPolygon25D: 06687 case QGis::WKBMultiPolygon: 06688 { 06689 QgsMultiPolygon mpolygon = asMultiPolygon(); 06690 06691 if ( partNum >= mpolygon.count() ) 06692 return false; 06693 06694 if ( ringNum >= mpolygon[partNum].count() ) 06695 return false; 06696 06697 mpolygon[partNum].remove( ringNum ); 06698 06699 QgsGeometry* g2 = QgsGeometry::fromMultiPolygon( mpolygon ); 06700 *this = *g2; 06701 delete g2; 06702 return true; 06703 } 06704 06705 default: 06706 return false; // only makes sense with polygons and multipolygons 06707 } 06708 } 06709 06710 06711 bool QgsGeometry::deletePart( int partNum ) 06712 { 06713 if ( partNum < 0 ) 06714 return false; 06715 06716 switch ( wkbType() ) 06717 { 06718 case QGis::WKBMultiPoint25D: 06719 case QGis::WKBMultiPoint: 06720 { 06721 QgsMultiPoint mpoint = asMultiPoint(); 06722 06723 if ( partNum >= mpoint.size() || mpoint.size() == 1 ) 06724 return false; 06725 06726 mpoint.remove( partNum ); 06727 06728 QgsGeometry* g2 = QgsGeometry::fromMultiPoint( mpoint ); 06729 *this = *g2; 06730 delete g2; 06731 break; 06732 } 06733 06734 case QGis::WKBMultiLineString25D: 06735 case QGis::WKBMultiLineString: 06736 { 06737 QgsMultiPolyline mline = asMultiPolyline(); 06738 06739 if ( partNum >= mline.size() || mline.size() == 1 ) 06740 return false; 06741 06742 mline.remove( partNum ); 06743 06744 QgsGeometry* g2 = QgsGeometry::fromMultiPolyline( mline ); 06745 *this = *g2; 06746 delete g2; 06747 break; 06748 } 06749 06750 case QGis::WKBMultiPolygon25D: 06751 case QGis::WKBMultiPolygon: 06752 { 06753 QgsMultiPolygon mpolygon = asMultiPolygon(); 06754 06755 if ( partNum >= mpolygon.size() || mpolygon.size() == 1 ) 06756 return false; 06757 06758 mpolygon.remove( partNum ); 06759 06760 QgsGeometry* g2 = QgsGeometry::fromMultiPolygon( mpolygon ); 06761 *this = *g2; 06762 delete g2; 06763 break; 06764 } 06765 06766 default: 06767 // single part geometries are ignored 06768 return false; 06769 } 06770 06771 return true; 06772 } 06773 06774 int QgsGeometry::avoidIntersections( QMap<QgsVectorLayer*, QSet< QgsFeatureId > > ignoreFeatures ) 06775 { 06776 int returnValue = 0; 06777 06778 //check if g has polygon type 06779 if ( type() != QGis::Polygon ) 06780 { 06781 return 1; 06782 } 06783 06784 QGis::WkbType geomTypeBeforeModification = wkbType(); 06785 06786 //read avoid intersections list from project properties 06787 bool listReadOk; 06788 QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", QStringList(), &listReadOk ); 06789 if ( !listReadOk ) 06790 { 06791 return true; //no intersections stored in project does not mean error 06792 } 06793 06794 //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each 06795 QgsVectorLayer* currentLayer = 0; 06796 QStringList::const_iterator aIt = avoidIntersectionsList.constBegin(); 06797 for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt ) 06798 { 06799 currentLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( *aIt ) ); 06800 if ( currentLayer ) 06801 { 06802 QgsFeatureIds ignoreIds; 06803 QMap<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer ); 06804 if ( ignoreIt != ignoreFeatures.constEnd() ) 06805 { 06806 ignoreIds = ignoreIt.value(); 06807 } 06808 06809 if ( currentLayer->removePolygonIntersections( this, ignoreIds ) != 0 ) 06810 { 06811 returnValue = 3; 06812 } 06813 } 06814 } 06815 06816 //make sure the geometry still has the same type (e.g. no change from polygon to multipolygon) 06817 if ( wkbType() != geomTypeBeforeModification ) 06818 { 06819 return 2; 06820 } 06821 06822 return returnValue; 06823 } 06824 06825 void QgsGeometry::validateGeometry( QList<Error> &errors ) 06826 { 06827 QgsGeometryValidator::validateGeometry( this, errors ); 06828 } 06829 06830 bool QgsGeometry::isGeosValid() 06831 { 06832 try 06833 { 06834 GEOSGeometry *g = asGeos(); 06835 06836 if ( !g ) 06837 return false; 06838 06839 return GEOSisValid( g ); 06840 } 06841 catch ( GEOSException &e ) 06842 { 06843 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 06844 return false; 06845 } 06846 } 06847 06848 bool QgsGeometry::isGeosEqual( QgsGeometry &g ) 06849 { 06850 return geosRelOp( GEOSEquals, this, &g ); 06851 } 06852 06853 bool QgsGeometry::isGeosEmpty() 06854 { 06855 try 06856 { 06857 GEOSGeometry *g = asGeos(); 06858 06859 if ( !g ) 06860 return false; 06861 06862 return GEOSisEmpty( g ); 06863 } 06864 catch ( GEOSException &e ) 06865 { 06866 QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); 06867 return false; 06868 } 06869 } 06870 06871 double QgsGeometry::leftOf( double x, double y, double& x1, double& y1, double& x2, double& y2 ) 06872 { 06873 double f1 = x - x1; 06874 double f2 = y2 - y1; 06875 double f3 = y - y1; 06876 double f4 = x2 - x1; 06877 return f1*f2 - f3*f4; 06878 }