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