[QGIS Commit] r12830 - in trunk/qgis: python/core src/app src/core
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sun Jan 24 11:07:56 EST 2010
Author: jef
Date: 2010-01-24 11:07:55 -0500 (Sun, 24 Jan 2010)
New Revision: 12830
Modified:
trunk/qgis/python/core/qgsgeometry.sip
trunk/qgis/src/app/qgsmaptooladdfeature.cpp
trunk/qgis/src/app/qgsmaptooladdisland.cpp
trunk/qgis/src/app/qgsmaptooladdring.cpp
trunk/qgis/src/app/qgsmaptoolcapture.cpp
trunk/qgis/src/app/qgsmaptoolcapture.h
trunk/qgis/src/app/qgsmaptoolnodetool.cpp
trunk/qgis/src/app/qgsmaptoolreshape.cpp
trunk/qgis/src/app/qgsmaptoolsplitfeatures.cpp
trunk/qgis/src/core/qgsgeometry.cpp
trunk/qgis/src/core/qgsgeometry.h
Log:
[FEATURE] add validation to capture tool
Modified: trunk/qgis/python/core/qgsgeometry.sip
===================================================================
--- trunk/qgis/python/core/qgsgeometry.sip 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/python/core/qgsgeometry.sip 2010-01-24 16:07:55 UTC (rev 12830)
@@ -90,6 +90,16 @@
/** Returns true if wkb of the geometry is of WKBMulti* type */
bool isMultipart();
+ /** compare geometries using GEOS
+ @note added in 1.5
+ */
+ bool isGeosEqual( QgsGeometry & );
+
+ /** check validity using GEOS
+ @note added in 1.5
+ */
+ bool isGeosValid();
+
/**
Set the geometry, feeding in a geometry in GEOS format.
*/
Modified: trunk/qgis/src/app/qgsmaptooladdfeature.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptooladdfeature.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptooladdfeature.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -59,11 +59,7 @@
layerWKBType == QGis::WKBMultiLineString25D || layerWKBType == QGis::WKBPoint25D || layerWKBType == QGis::WKBMultiPoint25D )
{
QMessageBox::critical( 0, tr( "2.5D shape type not supported" ), tr( "Adding features to 2.5D shapetypes is not supported yet" ) );
- delete mRubberBand;
- mRubberBand = NULL;
- mCapturing = FALSE;
- mCaptureList.clear();
- mCanvas->refresh();
+ stopCapturing();
return;
}
@@ -85,7 +81,7 @@
}
// POINT CAPTURING
- if ( mCaptureMode == CapturePoint )
+ if ( mode() == CapturePoint )
{
//check we only use this tool for point/multipoint layers
if ( vlayer->geometryType() != QGis::Point )
@@ -129,7 +125,7 @@
QgsFeature* f = new QgsFeature( 0, "WKBPoint" );
int size = 0;
- char end = QgsApplication::endian();
+ char endian = QgsApplication::endian();
unsigned char *wkb = NULL;
int wkbtype = 0;
double x = savePoint.x();
@@ -140,7 +136,7 @@
size = 1 + sizeof( int ) + 2 * sizeof( double );
wkb = new unsigned char[size];
wkbtype = QGis::WKBPoint;
- memcpy( &wkb[0], &end, 1 );
+ memcpy( &wkb[0], &endian, 1 );
memcpy( &wkb[1], &wkbtype, sizeof( int ) );
memcpy( &wkb[5], &x, sizeof( double ) );
memcpy( &wkb[5] + sizeof( double ), &y, sizeof( double ) );
@@ -151,14 +147,14 @@
wkb = new unsigned char[size];
wkbtype = QGis::WKBMultiPoint;
int position = 0;
- memcpy( &wkb[position], &end, 1 );
+ memcpy( &wkb[position], &endian, 1 );
position += 1;
memcpy( &wkb[position], &wkbtype, sizeof( int ) );
position += sizeof( int );
int npoint = 1;
memcpy( &wkb[position], &npoint, sizeof( int ) );
position += sizeof( int );
- memcpy( &wkb[position], &end, 1 );
+ memcpy( &wkb[position], &endian, 1 );
position += 1;
int pointtype = QGis::WKBPoint;
memcpy( &wkb[position], &pointtype, sizeof( int ) );
@@ -209,10 +205,10 @@
}
}
- else if ( mCaptureMode == CaptureLine || mCaptureMode == CapturePolygon )
+ else if ( mode() == CaptureLine || mode() == CapturePolygon )
{
//check we only use the line tool for line/multiline layers
- if ( mCaptureMode == CaptureLine && vlayer->geometryType() != QGis::Line )
+ if ( mode() == CaptureLine && vlayer->geometryType() != QGis::Line )
{
QMessageBox::information( 0, tr( "Wrong editing tool" ),
tr( "Cannot apply the 'capture line' tool on this vector layer" ) );
@@ -220,7 +216,7 @@
}
//check we only use the polygon tool for polygon/multipolygon layers
- if ( mCaptureMode == CapturePolygon && vlayer->geometryType() != QGis::Polygon )
+ if ( mode() == CapturePolygon && vlayer->geometryType() != QGis::Polygon )
{
QMessageBox::information( 0, tr( "Wrong editing tool" ),
tr( "Cannot apply the 'capture polygon' tool on this vector layer" ) );
@@ -244,52 +240,46 @@
if ( e->button() == Qt::LeftButton )
{
- mCapturing = TRUE;
+ startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
// End of string
- mCapturing = FALSE;
-
//lines: bail out if there are not at least two vertices
- if ( mCaptureMode == CaptureLine && mCaptureList.size() < 2 )
+ if ( mode() == CaptureLine && size() < 2 )
{
- delete mRubberBand;
- mRubberBand = NULL;
- mCaptureList.clear();
+ stopCapturing();
return;
}
//polygons: bail out if there are not at least two vertices
- if ( mCaptureMode == CapturePolygon && mCaptureList.size() < 3 )
+ if ( mode() == CapturePolygon && size() < 3 )
{
- delete mRubberBand;
- mRubberBand = NULL;
- mCaptureList.clear();
+ stopCapturing();
return;
}
//create QgsFeature with wkb representation
QgsFeature* f = new QgsFeature( 0, "WKBLineString" );
unsigned char* wkb;
- int size;
- char end = QgsApplication::endian();
+ int wkbsize;
+ char endian = QgsApplication::endian();
- if ( mCaptureMode == CaptureLine )
+ if ( mode() == CaptureLine )
{
if ( layerWKBType == QGis::WKBLineString )
{
- size = 1 + 2 * sizeof( int ) + 2 * mCaptureList.size() * sizeof( double );
- wkb = new unsigned char[size];
+ wkbsize = 1 + 2 * sizeof( int ) + 2 * size() * sizeof( double );
+ wkb = new unsigned char[wkbsize];
int wkbtype = QGis::WKBLineString;
- int length = mCaptureList.size();
- memcpy( &wkb[0], &end, 1 );
+ int length = size();
+ memcpy( &wkb[0], &endian, 1 );
memcpy( &wkb[1], &wkbtype, sizeof( int ) );
memcpy( &wkb[1+sizeof( int )], &length, sizeof( int ) );
int position = 1 + 2 * sizeof( int );
double x, y;
- for ( QList<QgsPoint>::iterator it = mCaptureList.begin(); it != mCaptureList.end(); ++it )
+ for ( QList<QgsPoint>::iterator it = begin(); it != end(); ++it )
{
QgsPoint savePoint = *it;
x = savePoint.x();
@@ -304,27 +294,27 @@
}
else if ( layerWKBType == QGis::WKBMultiLineString )
{
- size = 1 + 2 * sizeof( int ) + 1 + 2 * sizeof( int ) + 2 * mCaptureList.size() * sizeof( double );
- wkb = new unsigned char[size];
+ wkbsize = 1 + 2 * sizeof( int ) + 1 + 2 * sizeof( int ) + 2 * size() * sizeof( double );
+ wkb = new unsigned char[wkbsize];
int position = 0;
int wkbtype = QGis::WKBMultiLineString;
- memcpy( &wkb[position], &end, 1 );
+ memcpy( &wkb[position], &endian, 1 );
position += 1;
memcpy( &wkb[position], &wkbtype, sizeof( int ) );
position += sizeof( int );
int nlines = 1;
memcpy( &wkb[position], &nlines, sizeof( int ) );
position += sizeof( int );
- memcpy( &wkb[position], &end, 1 );
+ memcpy( &wkb[position], &endian, 1 );
position += 1;
int linewkbtype = QGis::WKBLineString;
memcpy( &wkb[position], &linewkbtype, sizeof( int ) );
position += sizeof( int );
- int length = mCaptureList.size();
+ int length = size();
memcpy( &wkb[position], &length, sizeof( int ) );
position += sizeof( int );
double x, y;
- for ( QList<QgsPoint>::iterator it = mCaptureList.begin(); it != mCaptureList.end(); ++it )
+ for ( QList<QgsPoint>::iterator it = begin(); it != end(); ++it )
{
QgsPoint savePoint = *it;
x = savePoint.x();
@@ -340,30 +330,28 @@
else
{
QMessageBox::critical( 0, tr( "Error" ), tr( "Cannot add feature. Unknown WKB type" ) );
- delete mRubberBand;
- mRubberBand = NULL;
- mCaptureList.clear();
+ stopCapturing();
return; //unknown wkbtype
}
- f->setGeometryAndOwnership( &wkb[0], size );
+ f->setGeometryAndOwnership( &wkb[0], wkbsize );
}
else // polygon
{
if ( layerWKBType == QGis::WKBPolygon )
{
- size = 1 + 3 * sizeof( int ) + 2 * ( mCaptureList.size() + 1 ) * sizeof( double );
- wkb = new unsigned char[size];
+ wkbsize = 1 + 3 * sizeof( int ) + 2 * ( size() + 1 ) * sizeof( double );
+ wkb = new unsigned char[wkbsize];
int wkbtype = QGis::WKBPolygon;
- int length = mCaptureList.size() + 1;//+1 because the first point is needed twice
+ int length = size() + 1;//+1 because the first point is needed twice
int numrings = 1;
- memcpy( &wkb[0], &end, 1 );
+ memcpy( &wkb[0], &endian, 1 );
memcpy( &wkb[1], &wkbtype, sizeof( int ) );
memcpy( &wkb[1+sizeof( int )], &numrings, sizeof( int ) );
memcpy( &wkb[1+2*sizeof( int )], &length, sizeof( int ) );
int position = 1 + 3 * sizeof( int );
double x, y;
QList<QgsPoint>::iterator it;
- for ( it = mCaptureList.begin(); it != mCaptureList.end(); ++it )
+ for ( it = begin(); it != end(); ++it )
{
QgsPoint savePoint = *it;
x = savePoint.x();
@@ -376,7 +364,7 @@
position += sizeof( double );
}
// close the polygon
- it = mCaptureList.begin();
+ it = begin();
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
@@ -388,21 +376,21 @@
}
else if ( layerWKBType == QGis::WKBMultiPolygon )
{
- size = 2 + 5 * sizeof( int ) + 2 * ( mCaptureList.size() + 1 ) * sizeof( double );
- wkb = new unsigned char[size];
+ wkbsize = 2 + 5 * sizeof( int ) + 2 * ( size() + 1 ) * sizeof( double );
+ wkb = new unsigned char[wkbsize];
int wkbtype = QGis::WKBMultiPolygon;
int polygontype = QGis::WKBPolygon;
- int length = mCaptureList.size() + 1;//+1 because the first point is needed twice
+ int length = size() + 1;//+1 because the first point is needed twice
int numrings = 1;
int numpolygons = 1;
int position = 0; //pointer position relative to &wkb[0]
- memcpy( &wkb[position], &end, 1 );
+ memcpy( &wkb[position], &endian, 1 );
position += 1;
memcpy( &wkb[position], &wkbtype, sizeof( int ) );
position += sizeof( int );
memcpy( &wkb[position], &numpolygons, sizeof( int ) );
position += sizeof( int );
- memcpy( &wkb[position], &end, 1 );
+ memcpy( &wkb[position], &endian, 1 );
position += 1;
memcpy( &wkb[position], &polygontype, sizeof( int ) );
position += sizeof( int );
@@ -412,7 +400,7 @@
position += sizeof( int );
double x, y;
QList<QgsPoint>::iterator it;
- for ( it = mCaptureList.begin(); it != mCaptureList.end(); ++it )//add the captured points to the polygon
+ for ( it = begin(); it != end(); ++it )//add the captured points to the polygon
{
QgsPoint savePoint = *it;
x = savePoint.x();
@@ -425,7 +413,7 @@
position += sizeof( double );
}
// close the polygon
- it = mCaptureList.begin();
+ it = begin();
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
@@ -436,12 +424,10 @@
else
{
QMessageBox::critical( 0, tr( "Error" ), tr( "Cannot add feature. Unknown WKB type" ) );
- delete mRubberBand;
- mRubberBand = NULL;
- mCaptureList.clear();
+ stopCapturing();
return; //unknown wkbtype
}
- f->setGeometryAndOwnership( &wkb[0], size );
+ f->setGeometryAndOwnership( &wkb[0], wkbsize );
int avoidIntersectionsReturn = f->geometry()->avoidIntersections();
if ( avoidIntersectionsReturn == 1 )
@@ -453,9 +439,7 @@
//bail out...
QMessageBox::critical( 0, tr( "Error" ), tr( "The feature could not be added because removing the polygon intersections would change the geometry type" ) );
delete f;
- delete mRubberBand;
- mRubberBand = 0;
- mCaptureList.clear();
+ stopCapturing();
return;
}
else if ( avoidIntersectionsReturn == 3 )
@@ -510,12 +494,7 @@
}
delete f;
- delete mRubberBand;
- mRubberBand = NULL;
-
- // delete the elements of mCaptureList
- mCaptureList.clear();
- mCanvas->refresh();
+ stopCapturing();
}
}
}
Modified: trunk/qgis/src/app/qgsmaptooladdisland.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptooladdisland.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptooladdisland.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -70,9 +70,7 @@
if ( !selectionErrorMsg.isEmpty() )
{
QMessageBox::critical( 0, tr( "Error, could not add island" ), selectionErrorMsg );
- mCaptureList.clear();
- delete mRubberBand;
- mRubberBand = 0;
+ stopCapturing();
return;
}
@@ -94,18 +92,15 @@
if ( e->button() == Qt::LeftButton )
{
- mCapturing = TRUE;
+ startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
- mCapturing = FALSE;
- delete mRubberBand;
- mRubberBand = 0;
-
//close polygon
- mCaptureList.push_back( *mCaptureList.begin() );
+ closePolygon();
+
vlayer->beginEditCommand( tr( "Part added" ) );
- int errorCode = vlayer->addIsland( mCaptureList );
+ int errorCode = vlayer->addIsland( points() );
QString errorMessage;
if ( errorCode != 0 )
@@ -144,13 +139,12 @@
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
if ( topologicalEditing )
{
- addTopologicalPoints( mCaptureList );
+ addTopologicalPoints( points() );
}
vlayer->endEditCommand();
}
- mCaptureList.clear();
- mCanvas->refresh();
+ stopCapturing();
}
}
Modified: trunk/qgis/src/app/qgsmaptooladdring.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptooladdring.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptooladdring.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -70,19 +70,14 @@
if ( e->button() == Qt::LeftButton )
{
- mCapturing = TRUE;
+ startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
- mCapturing = FALSE;
- delete mRubberBand;
- mRubberBand = 0;
+ closePolygon();
- //close polygon
- mCaptureList.push_back( *mCaptureList.begin() );
-
vlayer->beginEditCommand( tr( "Ring added" ) );
- int addRingReturnCode = vlayer->addRing( mCaptureList );
+ int addRingReturnCode = vlayer->addRing( points() );
if ( addRingReturnCode != 0 )
{
QString errorMessage;
@@ -118,7 +113,7 @@
{
vlayer->endEditCommand();
}
- mCaptureList.clear();
- mCanvas->refresh();
+
+ stopCapturing();
}
}
Modified: trunk/qgis/src/app/qgsmaptoolcapture.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolcapture.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptoolcapture.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -14,32 +14,27 @@
***************************************************************************/
/* $Id$ */
-#include "qgsapplication.h"
-#include "qgsattributedialog.h"
-#include "qgscoordinatetransform.h"
-#include "qgsfield.h"
-#include "qgslogger.h"
-#include "qgsgeometry.h"
#include "qgsmaptoolcapture.h"
+
+#include "qgisapp.h"
+#include "qgsvertexmarker.h"
+#include "qgscursors.h"
+#include "qgsrubberband.h"
#include "qgsmapcanvas.h"
#include "qgsmaprenderer.h"
-#include "qgsmaptopixel.h"
-#include "qgsfeature.h"
-#include "qgsproject.h"
-#include "qgsrubberband.h"
#include "qgsvectorlayer.h"
-#include "qgsvectordataprovider.h"
-#include "qgscursors.h"
+
#include <QCursor>
#include <QPixmap>
#include <QMessageBox>
#include <QMouseEvent>
+#include <QStatusBar>
QgsMapToolCapture::QgsMapToolCapture( QgsMapCanvas* canvas, enum CaptureMode tool )
: QgsMapToolEdit( canvas ), mCaptureMode( tool ), mRubberBand( 0 )
{
- mCapturing = FALSE;
+ mCapturing = false;
QPixmap mySelectQPixmap = QPixmap(( const char ** ) capture_point_cursor );
mCursor = QCursor( mySelectQPixmap, 8, 8 );
@@ -49,8 +44,7 @@
QgsMapToolCapture::~QgsMapToolCapture()
{
- delete mRubberBand;
- mRubberBand = 0;
+ stopCapturing();
}
void QgsMapToolCapture::canvasMoveEvent( QMouseEvent * e )
@@ -80,10 +74,7 @@
void QgsMapToolCapture::deactivate()
{
- delete mRubberBand;
- mRubberBand = 0;
- mCaptureList.clear();
-
+ stopCapturing();
QgsMapTool::deactivate();
}
@@ -129,7 +120,9 @@
return 2;
}
mRubberBand->addPoint( mapPoint );
- mCaptureList.push_back( layerPoint );
+ mCaptureList.append( layerPoint );
+
+ validateGeometry();
}
return 0;
@@ -148,14 +141,96 @@
}
mRubberBand->removeLastPoint();
- mCaptureList.pop_back();
+ mCaptureList.removeLast();
+
+ validateGeometry();
}
}
void QgsMapToolCapture::keyPressEvent( QKeyEvent* e )
{
- if ( e->key() == Qt::Key_Backspace )
+ if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete )
{
undo();
}
}
+
+void QgsMapToolCapture::startCapturing()
+{
+ mCapturing = true;
+}
+
+void QgsMapToolCapture::stopCapturing()
+{
+ if ( mRubberBand )
+ {
+ delete mRubberBand;
+ mRubberBand = 0;
+ }
+
+ while ( !mGeomErrorMarkers.isEmpty() )
+ {
+ delete mGeomErrorMarkers.takeFirst();
+ }
+
+ mGeomErrors.clear();
+
+ mCapturing = false;
+ mCaptureList.clear();
+ mCanvas->refresh();
+}
+
+void QgsMapToolCapture::closePolygon()
+{
+ mCaptureList.append( mCaptureList[0] );
+}
+
+void QgsMapToolCapture::validateGeometry()
+{
+ QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
+
+ mGeomErrors.clear();
+
+ while ( !mGeomErrorMarkers.isEmpty() )
+ {
+ delete mGeomErrorMarkers.takeFirst();
+ }
+
+ switch ( mCaptureMode )
+ {
+ case CapturePoint:
+ return;
+ case CaptureLine:
+ if ( mCaptureList.size() < 2 )
+ return;
+ QgsGeometry::validatePolyline( mGeomErrors, 0, mCaptureList.toVector() );
+ break;
+ case CapturePolygon:
+ if ( mCaptureList.size() < 3 )
+ return;
+ QgsGeometry::validatePolyline( mGeomErrors, 0, mCaptureList.toVector() << mCaptureList[0], true );
+ break;
+ }
+
+ QString tip;
+ for ( int i = 0; i < mGeomErrors.size(); i++ )
+ {
+ tip += mGeomErrors[i].what() + "\n";
+ if ( !mGeomErrors[i].hasWhere() )
+ continue;
+
+ QgsVertexMarker *vm = new QgsVertexMarker( mCanvas );
+ vm->setCenter( mCanvas->mapRenderer()->layerToMapCoordinates( vlayer, mGeomErrors[i].where() ) );
+ vm->setIconType( QgsVertexMarker::ICON_X );
+ vm->setPenWidth( 2 );
+ vm->setToolTip( mGeomErrors[i].what() );
+ vm->setColor( Qt::green );
+ vm->setZValue( vm->zValue() + 1 );
+ mGeomErrorMarkers << vm;
+ }
+
+ QStatusBar *sb = QgisApp::instance()->statusBar();
+ sb->showMessage( QObject::tr( "%n geometry error(s) found.", "number of geometry errors", mGeomErrors.size() ) );
+ if ( !tip.isEmpty() )
+ sb->setToolTip( tip );
+}
Modified: trunk/qgis/src/app/qgsmaptoolcapture.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoolcapture.h 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptoolcapture.h 2010-01-24 16:07:55 UTC (rev 12830)
@@ -20,9 +20,11 @@
#include "qgsmapcanvassnapper.h"
#include "qgsmaptooledit.h"
#include "qgspoint.h"
+#include "qgsgeometry.h"
class QgsGeometry;
class QgsRubberBand;
+class QgsVertexMarker;
#include <QPoint>
#include <QList>
@@ -69,7 +71,26 @@
*/
protected:
+ /**Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates)
+ @return 0 in case of success, 1 if current layer is not a vector layer, 2 if coordinate transformation failed*/
+ int addVertex( const QPoint& p );
+ /**Removes the last vertex from mRubberBand and mCaptureList*/
+ void undo();
+
+ void startCapturing();
+ void stopCapturing();
+
+ CaptureMode mode() { return mCaptureMode; }
+
+
+ int size() { return mCaptureList.size(); }
+ QList<QgsPoint>::iterator begin() { return mCaptureList.begin(); }
+ QList<QgsPoint>::iterator end() { return mCaptureList.end(); }
+ const QList<QgsPoint> &points() { return mCaptureList; }
+ void closePolygon();
+
+ private:
/** which capturing tool is being used */
enum CaptureMode mCaptureMode;
@@ -82,13 +103,9 @@
/** List to store the points of digitised lines and polygons (in layer coordinates)*/
QList<QgsPoint> mCaptureList;
- /**Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates)
- @return 0 in case of success, 1 if current layer is not a vector layer, 2 if coordinate transformation failed*/
- int addVertex( const QPoint& p );
-
- /**Removes the last vertex from mRubberBand and mCaptureList*/
- void undo();
-
+ void validateGeometry();
+ QList< QgsGeometry::Error > mGeomErrors;
+ QList< QgsVertexMarker * > mGeomErrorMarkers;
};
#endif
Modified: trunk/qgis/src/app/qgsmaptoolnodetool.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolnodetool.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptoolnodetool.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -53,8 +53,6 @@
return marker;
}
-
-
QgsMapToolNodeTool::QgsMapToolNodeTool( QgsMapCanvas* canvas ): QgsMapToolVertexEdit( canvas )
{
mSelectionFeature = NULL;
@@ -121,20 +119,10 @@
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
if ( mSelectionFeature != NULL && !mChangingGeometry && ( vlayer->featureAtId( mSelectionFeature->featureId(), feat, true, false ) ) )
{
- try
+ if ( !feat.geometry()->isGeosEqual( *mSelectionFeature->feature()->geometry() ) )
{
- if ( !GEOSEquals( feat.geometry()->asGeos(), mSelectionFeature->feature()->geometry()->asGeos() ) )
- {
- mSelectionFeature->updateFromFeature();
- //throw error
- }
- }
- catch ( ... )
- {
- //GEOS is throwing exception when polygon is not valid to be able to edit it
- //Only possibility to fix this operation since node tool doesn't allow to store invalid geometry after editing
mSelectionFeature->updateFromFeature();
- //if it does update markers just to be sure of correctness
+ //throw error
}
}
}
@@ -474,7 +462,7 @@
}
try
{
- if ( !GEOSEquals( feat.geometry()->asGeos(), mSelectionFeature->feature()->geometry()->asGeos() ) )
+ if ( !feat.geometry()->isGeosEqual( *mSelectionFeature->feature()->geometry() ) )
{
//update markers when geometries are not valid
mSelectionFeature->updateFromFeature();
@@ -1032,7 +1020,7 @@
mVlayer->featureAtId( mFeatureId, f, true, false );
bool wasValid = false; // mGeomErrors.isEmpty();
- bool isValid = GEOSisValid( f.geometry()->asGeos() );
+ bool isValid = f.geometry()->isGeosValid();
if ( wasValid && !isValid )
{
QMessageBox::warning( NULL,
@@ -1106,7 +1094,7 @@
QgsFeature f;
mVlayer->featureAtId( mFeatureId, f, true, false );
bool wasValid = false; // mGeomErrors.isEmpty();
- bool isValid = GEOSisValid( f.geometry()->asGeos() );
+ bool isValid = f.geometry()->isGeosValid();
if ( wasValid && !isValid )
{
QMessageBox::warning( NULL,
Modified: trunk/qgis/src/app/qgsmaptoolreshape.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolreshape.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptoolreshape.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -69,24 +69,21 @@
if ( e->button() == Qt::LeftButton )
{
- mCapturing = TRUE;
+ startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
- mCapturing = FALSE;
- delete mRubberBand;
- mRubberBand = 0;
-
//find out bounding box of mCaptureList
- if ( mCaptureList.size() < 1 )
+ if ( size() < 1 )
{
+ stopCapturing();
return;
}
- QgsPoint firstPoint = mCaptureList.at( 0 );
+ QgsPoint firstPoint = points().at( 0 );
QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
- for ( int i = 1; i < mCaptureList.size(); ++i )
+ for ( int i = 1; i < size(); ++i )
{
- bbox.combineExtentWith( mCaptureList.at( i ).x(), mCaptureList.at( i ).y() );
+ bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
}
//query all the features that intersect bounding box of capture line
@@ -104,7 +101,7 @@
QgsGeometry* geom = f.geometry();
if ( geom )
{
- reshapeReturn = geom->reshapeGeometry( mCaptureList );
+ reshapeReturn = geom->reshapeGeometry( points() );
if ( reshapeReturn == 0 )
{
vlayer->changeGeometry( f.id(), geom );
@@ -122,7 +119,6 @@
vlayer->destroyEditCommand();
}
- mCaptureList.clear();
- mCanvas->refresh();
+ stopCapturing();
}
}
Modified: trunk/qgis/src/app/qgsmaptoolsplitfeatures.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolsplitfeatures.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/app/qgsmaptoolsplitfeatures.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -69,18 +69,14 @@
if ( e->button() == Qt::LeftButton )
{
- mCapturing = TRUE;
+ startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
- mCapturing = FALSE;
- delete mRubberBand;
- mRubberBand = 0;
-
//bring up dialog if a split was not possible (polygon) or only done once (line)
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
vlayer->beginEditCommand( tr( "Features split" ) );
- int returnCode = vlayer->splitFeatures( mCaptureList, topologicalEditing );
+ int returnCode = vlayer->splitFeatures( points(), topologicalEditing );
vlayer->endEditCommand();
if ( returnCode == 4 )
{
@@ -92,7 +88,6 @@
QMessageBox::warning( 0, tr( "Split error" ), tr( "An error occured during feature splitting" ) );
}
- mCaptureList.clear();
- mCanvas->refresh();
+ stopCapturing();
}
}
Modified: trunk/qgis/src/core/qgsgeometry.cpp
===================================================================
--- trunk/qgis/src/core/qgsgeometry.cpp 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/core/qgsgeometry.cpp 2010-01-24 16:07:55 UTC (rev 12830)
@@ -44,14 +44,11 @@
class GEOSException
{
public:
- GEOSException( const char *theMsg )
+ GEOSException( QString theMsg )
{
- if ( strcmp( theMsg, "Unknown exception thrown" ) == 0 && lastMsg )
+ if ( theMsg == "Unknown exception thrown" && lastMsg.isNull() )
{
- delete [] theMsg;
- char *aMsg = new char[strlen( lastMsg )+1];
- strcpy( aMsg, lastMsg );
- msg = aMsg;
+ msg = theMsg;
}
else
{
@@ -69,47 +66,46 @@
~GEOSException()
{
if ( lastMsg == msg )
- lastMsg = NULL;
- delete [] msg;
+ lastMsg = QString::null;
}
- const char *what()
+ QString what()
{
return msg;
}
private:
- const char *msg;
- static const char *lastMsg;
+ QString msg;
+ static QString lastMsg;
};
-const char *GEOSException::lastMsg = NULL;
+QString GEOSException::lastMsg;
static void throwGEOSException( const char *fmt, ... )
{
va_list ap;
+ char buffer[1024];
+
va_start( ap, fmt );
- size_t buflen = vsnprintf( NULL, 0, fmt, ap );
- char *msg = new char[buflen+1];
- vsnprintf( msg, buflen + 1, fmt, ap );
+ vsnprintf( buffer, sizeof buffer, fmt, ap );
va_end( ap );
- QgsDebugMsg( QString( "GEOS exception encountered: %1" ).arg( msg ) );
+ QgsDebugMsg( QString( "GEOS exception encountered: %1" ).arg( buffer ) );
- throw GEOSException( msg );
+ throw GEOSException( QString::fromUtf8( buffer ) );
}
static void printGEOSNotice( const char *fmt, ... )
{
#if defined(QGISDEBUG)
va_list ap;
+ char buffer[1024];
+
va_start( ap, fmt );
- size_t buflen = vsnprintf( NULL, 0, fmt, ap );
- char *msg = new char[buflen+1];
- vsnprintf( msg, buflen + 1, fmt, ap );
+ vsnprintf( buffer, sizeof buffer, fmt, ap );
va_end( ap );
- QgsDebugMsg( QString( "GEOS notice: " ).arg( msg ) );
- delete [] msg;
+
+ QgsDebugMsg( QString( "GEOS notice: %1" ).arg( QString::fromUtf8( buffer ) ) );
#endif
}
@@ -3157,7 +3153,7 @@
return 0;
}
-int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries, bool topological, QList<QgsPoint>& topologyTestPoints )
+int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries, bool topological, QList<QgsPoint> &topologyTestPoints )
{
int returnCode = 0;
@@ -6366,58 +6362,86 @@
}
}
-void QgsGeometry::validatePolyline( QList<Error> &errors, int i, const QgsPolyline &line )
+void QgsGeometry::validatePolyline( QList<Error> &errors, int i, QgsPolyline line, bool ring )
{
- if ( line.size() < 2 )
+ if ( ring )
{
+ if ( line.size() < 3 )
+ {
+ QString msg = QObject::tr( "ring %1 with less than three points" ).arg( i );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ return;
+ }
+
+ if ( line[0] != line[ line.size()-1 ] )
+ {
+ QString msg = QObject::tr( "ring %1 not closed" ).arg( i );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ return;
+ }
+ }
+ else if ( line.size() < 2 )
+ {
QString msg = QObject::tr( "line %1 with less than two points" ).arg( i );
QgsDebugMsg( msg );
errors << Error( msg );
return;
}
- bool closed = line[0] == line[ line.size()-1 ];
+ int j = 0;
+ while ( j < line.size() - 1 )
+ {
+ int n = 0;
+ while ( j < line.size() && line[j] == line[j+1] )
+ {
+ line.remove( j );
+ n++;
+ }
- if ( closed && line.size() < 3 )
- {
- QString msg = QObject::tr( "ring %1 with less than three points" ).arg( i );
- QgsDebugMsg( msg );
- errors << Error( msg );
- return;
+ if ( n > 0 )
+ {
+ QString msg = QObject::tr( "line %1 contains %n duplicate node(s) at %2", "number of duplicate nodes", n ).arg( i ).arg( j );
+ QgsDebugMsg( msg );
+ errors << Error( msg, line[j] );
+ }
+
+ j++;
}
- for ( int j = 0; j < line.size() - 3; j++ )
+ for ( j = 0; j < line.size() - 3; j++ )
{
QgsVector v = line[j+1] - line[j];
+ double vl = v.length();
- int n = j == 0 && closed ? line.size() - 2 : line.size() - 1;
+ int n = ( j == 0 && ring ) ? line.size() - 2 : line.size() - 1;
for ( int k = j + 2; k < n; k++ )
{
QgsVector w = line[k+1] - line[k];
QgsPoint s;
- if ( intersectLines( line[j], v, line[k], w, s ) )
+ if ( !intersectLines( line[j], v, line[k], w, s ) )
+ continue;
+
+ double d = -distLine2Point( line[j], v.perpVector(), s );
+ if ( d < 0 || d > vl )
+ continue;
+
+ d = -distLine2Point( line[k], w.perpVector(), s );
+ if ( d < 0 || d > w.length() )
+ continue;
+
+ QString msg = QObject::tr( "segments %1 and %2 of line %3 intersect at %4" ).arg( j ).arg( k ).arg( i ).arg( s.toString() );
+ QgsDebugMsg( msg );
+ errors << Error( msg, s );
+ if ( errors.size() > 100 )
{
- double d = -distLine2Point( line[j], v.perpVector(), s );
-
- if ( d >= 0 && d <= v.length() )
- {
- d = -distLine2Point( line[k], w.perpVector(), s );
- if ( d >= 0 && d <= w.length() )
- {
- QString msg = QObject::tr( "segments %1 and %2 of line %3 intersect at %4" ).arg( j ).arg( k ).arg( i ).arg( s.toString() );
- QgsDebugMsg( msg );
- errors << Error( msg, s );
- if ( errors.size() > 100 )
- {
- QString msg = QObject::tr( "stopping validation after more than 100 errors" );
- QgsDebugMsg( msg );
- errors << Error( msg );
- return;
- }
- }
- }
+ QString msg = QObject::tr( "stopping validation after more than 100 errors" );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ return;
}
}
}
@@ -6448,7 +6472,7 @@
// check if rings are self-intersecting
for ( int i = 0; i < polygon.size(); i++ )
{
- validatePolyline( errors, i, polygon[i] );
+ validatePolyline( errors, i, polygon[i], true );
}
}
@@ -6521,3 +6545,41 @@
break;
}
}
+
+bool QgsGeometry::isGeosValid()
+{
+ try
+ {
+ GEOSGeometry *g = asGeos();
+
+ if ( !g )
+ return false;
+
+ return GEOSisValid( g );
+ }
+ catch ( GEOSException &e )
+ {
+ // looks like geometry is fubar
+ Q_UNUSED( e );
+ QgsDebugMsg( QString( "GEOS exception caught: %1" ).arg( e.what() ) );
+ return false;
+ }
+}
+
+bool QgsGeometry::isGeosEqual( QgsGeometry &g )
+{
+ try
+ {
+ GEOSGeometry *g0 = asGeos();
+ GEOSGeometry *g1 = g.asGeos();
+
+ return g0 && g1 && GEOSEquals( g0, g1 );
+ }
+ catch ( GEOSException &e )
+ {
+ // looks like geometry is fubar
+ Q_UNUSED( e );
+ QgsDebugMsg( QString( "GEOS exception caught: %1" ).arg( e.what() ) );
+ return false;
+ }
+}
Modified: trunk/qgis/src/core/qgsgeometry.h
===================================================================
--- trunk/qgis/src/core/qgsgeometry.h 2010-01-24 15:59:54 UTC (rev 12829)
+++ trunk/qgis/src/core/qgsgeometry.h 2010-01-24 16:07:55 UTC (rev 12830)
@@ -131,7 +131,16 @@
/** Returns true if wkb of the geometry is of WKBMulti* type */
bool isMultipart();
+ /** compare geometries using GEOS
+ @note added in 1.5
+ */
+ bool isGeosEqual( QgsGeometry & );
+ /** check validity using GEOS
+ @note added in 1.5
+ */
+ bool isGeosValid();
+
double distance( QgsGeometry& geom );
/**
@@ -250,7 +259,7 @@
int splitGeometry( const QList<QgsPoint>& splitLine,
QList<QgsGeometry*>&newGeometries,
bool topological,
- QList<QgsPoint>& topologyTestPoints );
+ QList<QgsPoint> &topologyTestPoints );
/**Replaces a part of this geometry with another line
@return 0 in case of success
@@ -379,6 +388,9 @@
void validateGeometry( QList<Error> &errors );
+ static void validatePolyline( QList<Error> &errors, int i, QgsPolyline polyline, bool ring = false );
+ static void validatePolygon( QList<Error> &errors, int i, const QgsPolygon &polygon );
+
private:
// Private variables
@@ -511,13 +523,10 @@
/** return polygon from wkb */
QgsPolygon asPolygon( unsigned char*& ptr, bool hasZValue );
- void checkRingIntersections( QList<Error> &errors,
- int p0, int i0, const QgsPolyline &ring0,
- int p1, int i1, const QgsPolyline &ring1 );
+ static void checkRingIntersections( QList<Error> &errors,
+ int p0, int i0, const QgsPolyline &ring0,
+ int p1, int i1, const QgsPolyline &ring1 );
- void validatePolyline( QList<Error> &errors, int i, const QgsPolyline &polygon );
- void validatePolygon( QList<Error> &errors, int i, const QgsPolygon &polygon );
-
static int refcount;
}; // class QgsGeometry
More information about the QGIS-commit
mailing list