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