Quantum GIS API Documentation  1.7.4
src/core/qgsgeometry.cpp
Go to the documentation of this file.
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, &currentCoordSeqSize );
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, &currentLength );
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines