Skip to content

Commit

Permalink
validation/geometry/threading fixes:
Browse files Browse the repository at this point in the history
- fTools/polygon centroids: catch missing centroid with invalid geometry
  (fixes #4963)
- fTools/validate geometry:
 * fix final position of progress bar
 * don't use isGeosValid()
 * zoom to feature on locationless errors (including OTFR support)
 * store/restore dialog position
- QgsGeometry(Validator):
 * log GEOS exceptions
 * (closed) rings need at least 4 points not 3
 * log error when geometry can't be exported to GEOS
 * don't produce "geometry is valid" error
- improve logging from threads
 * keep message output from main thread as popup
 * log message from threads to message log (fixes crash on python error
   in thread)
  • Loading branch information
jef-n committed May 25, 2012
1 parent d208b29 commit d751036
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 80 deletions.
4 changes: 2 additions & 2 deletions python/plugins/fTools/tools/doGeometry.py
Expand Up @@ -620,11 +620,11 @@ def polygon_centroids( self ):
self.emit( SIGNAL( "runStatus( PyQt_PyObject )" ), nElement )
inGeom = inFeat.geometry()
atMap = inFeat.attributeMap()
outGeom = QgsGeometry( inGeom.centroid() )
outGeom = inGeom.centroid()
if outGeom is None:
return "math_error"
outFeat.setAttributeMap( atMap )
outFeat.setGeometry( outGeom )
outFeat.setGeometry( QgsGeometry( outGeom ) )
writer.addFeature( outFeat )
del writer
return True
Expand Down
58 changes: 42 additions & 16 deletions python/plugins/fTools/tools/doValidate.py
Expand Up @@ -93,6 +93,15 @@ def __init__(self, iface):
self.storedScale = self.iface.mapCanvas().scale()
# create marker for error
self.marker = MarkerErrorGeometry(self.iface.mapCanvas())

settings = QSettings()
self.restoreGeometry( settings.value("/fTools/ValidateDialog/geometry").toByteArray() )

def closeEvent(self, e):
settings = QSettings()
settings.setValue( "/fTools/ValidateDialog/geometry", QVariant(self.saveGeometry()) )
QMainWindow.closeEvent(self, e)
del self.marker

def keyPressEvent( self, e ):
if ( e.modifiers() == Qt.ControlModifier or \
Expand All @@ -115,38 +124,56 @@ def accept( self ):
elif self.cmbField.isVisible() and self.cmbField.currentText() == "":
QMessageBox.information( self, self.tr("Error!"), self.tr( "Please specify input field" ) )
else:
self.validate( self.inShape.currentText(), self.useSelected.checkState() )
self.vlayer = ftools_utils.getVectorLayerByName( self.inShape.currentText() )
self.validate( self.useSelected.checkState() )

def zoomToError(self, curr, prev):
if curr is None:
return
row = curr.row() # if we clicked in the first column, we want the second
item = self.tblUnique.item(row, 1)

e = item.data(Qt.UserRole).toPyObject()
if e is None:
return

mc = self.iface.mapCanvas()
x = e.x()
y = e.y()
self.marker.setGeom(x, y) # Set Marker
mc.zoomToPreviousExtent()
scale = mc.scale()
rect = QgsRectangle(float(x)-(4.0/scale),float(y)-(4.0/scale),
float(x)+(4.0/scale),float(y)+(4.0/scale))

if mc.mapRenderer().hasCrsTransformEnabled():
ct = QgsCoordinateTransform( self.vlayer.crs(), mc.mapRenderer().destinationCrs() )

e = item.data(Qt.UserRole).toPyObject()

if type(e)==QgsPoint:
if not ct is None:
e = ct.transform( e )

self.marker.setGeom(e.x(), e.y())

rect = mc.extent()
rect.expand( 0.25, e )

else:
self.marker.reset()

ft = QgsFeature()
(fid,ok) = self.tblUnique.item(row, 0).text().toInt()
if not ok or not self.vlayer.featureAtId( fid, ft, True):
return

rect = ft.geometry().boundingBox()
if not ct is None:
rect = ct.transformBoundingBox( rect )
rect.expand(1.05)

# Set the extent to our new rectangle
mc.setExtent(rect)
# Refresh the map
mc.refresh()

def validate( self, myLayer, mySelection ):
vlayer = ftools_utils.getVectorLayerByName( myLayer )
def validate( self, mySelection ):
self.tblUnique.clearContents()
self.tblUnique.setRowCount( 0 )
self.lstCount.clear()
self.buttonOk.setEnabled( False )
self.testThread = validateThread( self.iface.mainWindow(), self, vlayer, mySelection )
self.testThread = validateThread( self.iface.mainWindow(), self, self.vlayer, mySelection )
QObject.connect( self.testThread, SIGNAL( "runFinished(PyQt_PyObject)" ), self.runFinishedFromThread )
QObject.connect( self.testThread, SIGNAL( "runStatus(PyQt_PyObject)" ), self.runStatusFromThread )
QObject.connect( self.testThread, SIGNAL( "runRange(PyQt_PyObject)" ), self.runRangeFromThread )
Expand Down Expand Up @@ -214,7 +241,6 @@ def run( self ):
self.running = True
output = self.check_geometry( self.vlayer )
self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), output )
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 100 )

def stop(self):
self.running = False
Expand Down Expand Up @@ -243,7 +269,7 @@ def check_geometry( self, vlayer ):
self.emit(SIGNAL("runStatus(PyQt_PyObject)"), nElement)
nElement += 1
# Check Add error
if not (geom.isGeosEmpty() or geom.isGeosValid() ) :
if not geom.isGeosEmpty():
lstErrors.append((feat.id(), list(geom.validateGeometry())))
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nFeat )
return lstErrors
6 changes: 5 additions & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -65,6 +65,7 @@
#include <QToolButton>
#include <QVBoxLayout>
#include <QWhatsThis>
#include <QThread>

#include <qgsnetworkaccessmanager.h>

Expand Down Expand Up @@ -318,7 +319,10 @@ static void setTitleBarText_( QWidget & qgisApp )
*/
static QgsMessageOutput *messageOutputViewer_()
{
return new QgsMessageViewer( QgisApp::instance() );
if ( QThread::currentThread() == QApplication::instance()->thread() )
return new QgsMessageViewer( QgisApp::instance() );
else
return new QgsMessageOutputConsole();
}

static void customSrsValidation_( QgsCoordinateReferenceSystem* srs )
Expand Down
1 change: 0 additions & 1 deletion src/app/qgscustomization.cpp
Expand Up @@ -35,7 +35,6 @@
#include <QToolButton>
#include <QStatusBar>
#include <QMetaObject>
#include <QThread>

#ifdef Q_OS_MACX
QgsCustomizationDialog::QgsCustomizationDialog( QWidget *parent )
Expand Down
59 changes: 31 additions & 28 deletions src/core/qgsgeometry.cpp
Expand Up @@ -22,6 +22,7 @@ email : morb at ozemail dot com dot au
#include "qgsgeometry.h"
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgspoint.h"
#include "qgsrectangle.h"

Expand All @@ -36,8 +37,7 @@ email : morb at ozemail dot com dot au
#define CATCH_GEOS(r) \
catch (GEOSException &e) \
{ \
Q_UNUSED(e); \
QgsDebugMsg("GEOS: " + QString( e.what() ) ); \
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr("GEOS") ); \
return r; \
}

Expand Down Expand Up @@ -90,7 +90,7 @@ static void throwGEOSException( const char *fmt, ... )
vsnprintf( buffer, sizeof buffer, fmt, ap );
va_end( ap );

QgsDebugMsg( QString( "GEOS exception encountered: %1" ).arg( buffer ) );
QgsDebugMsg( QString( "GEOS exception: %1" ).arg( buffer ) );

throw GEOSException( QString::fromUtf8( buffer ) );
}
Expand Down Expand Up @@ -166,7 +166,7 @@ static GEOSGeometry *cloneGeosGeom( const GEOSGeometry *geom )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
for ( int i = 0; i < geoms.count(); i++ )
GEOSGeom_destroy( geoms[i] );

Expand Down Expand Up @@ -261,7 +261,7 @@ static GEOSCoordSequence *createGeosCoordSequence( const QgsPolyline& points )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
/*if ( coord )
GEOSCoordSeq_destroy( coord );*/
throw;
Expand All @@ -285,7 +285,7 @@ static GEOSGeometry *createGeosCollection( int typeId, QVector<GEOSGeometry*> ge
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
}

delete [] geomarr;
Expand All @@ -304,7 +304,7 @@ static GEOSGeometry *createGeosLineString( const QgsPolyline& polyline )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
//MH: for strange reasons, geos3 crashes when removing the coordinate sequence
//if ( coord )
//GEOSCoordSeq_destroy( coord );
Expand Down Expand Up @@ -337,7 +337,7 @@ static GEOSGeometry *createGeosLinearRing( const QgsPolyline& polyline )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
/* as MH has noticed ^, this crashes geos
if ( coord )
GEOSCoordSeq_destroy( coord );*/
Expand Down Expand Up @@ -389,7 +389,7 @@ static GEOSGeometry *createGeosPolygon( const QgsPolygon& polygon )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
for ( int i = 0; i < geoms.count(); i++ )
GEOSGeom_destroy( geoms[i] );
return 0;
Expand Down Expand Up @@ -421,7 +421,7 @@ QgsGeometry* QgsGeometry::fromWkt( QString wkt )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
return 0;
}
}
Expand Down Expand Up @@ -456,7 +456,8 @@ QgsGeometry* QgsGeometry::fromMultiPoint( const QgsMultiPoint& multipoint )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

for ( int i = 0; i < geoms.size(); ++i )
GEOSGeom_destroy( geoms[i] );

Expand All @@ -477,7 +478,8 @@ QgsGeometry* QgsGeometry::fromMultiPolyline( const QgsMultiPolyline& multiline )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

for ( int i = 0; i < geoms.count(); i++ )
GEOSGeom_destroy( geoms[i] );

Expand All @@ -501,7 +503,8 @@ QgsGeometry* QgsGeometry::fromMultiPolygon( const QgsMultiPolygon& multipoly )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

for ( int i = 0; i < geoms.count(); i++ )
GEOSGeom_destroy( geoms[i] );

Expand Down Expand Up @@ -2394,7 +2397,7 @@ double QgsGeometry::closestVertexWithContext( const QgsPoint& point, int& atVert
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
return -1;
}

Expand Down Expand Up @@ -2706,7 +2709,8 @@ int QgsGeometry::addRing( const QList<QgsPoint>& ring )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

if ( newRingPolygon )
GEOSGeom_destroy( newRingPolygon );
else if ( newRing )
Expand Down Expand Up @@ -2739,7 +2743,8 @@ int QgsGeometry::addRing( const QList<QgsPoint>& ring )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

if ( shell )
GEOSGeom_destroy( shell );
else if ( shellRing )
Expand Down Expand Up @@ -2776,7 +2781,8 @@ int QgsGeometry::addRing( const QList<QgsPoint>& ring )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

if ( hole )
GEOSGeom_destroy( hole );
else if ( holeRing )
Expand Down Expand Up @@ -2924,7 +2930,8 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

if ( newRing )
GEOSGeom_destroy( newRing );

Expand All @@ -2947,7 +2954,7 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );

if ( newPart )
GEOSGeom_destroy( newPart );
Expand Down Expand Up @@ -3839,7 +3846,7 @@ bool QgsGeometry::contains( QgsPoint* p )
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
returnval = false;
}

Expand Down Expand Up @@ -5458,7 +5465,7 @@ GEOSGeometry* QgsGeometry::reshapePolygon( const GEOSGeometry* polygon, const GE
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
nIntersections = 0;
}

Expand Down Expand Up @@ -5569,7 +5576,7 @@ GEOSGeometry* QgsGeometry::reshapeLine( const GEOSGeometry* line, const GEOSGeom
}
catch ( GEOSException &e )
{
Q_UNUSED( e );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
atLeastTwoIntersections = false;
}

Expand Down Expand Up @@ -6724,9 +6731,7 @@ bool QgsGeometry::isGeosValid()
}
catch ( GEOSException &e )
{
// looks like geometry is fubar
Q_UNUSED( e );
QgsDebugMsg( QString( "GEOS exception caught: %1" ).arg( e.what() ) );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
return false;
}
}
Expand All @@ -6749,9 +6754,7 @@ bool QgsGeometry::isGeosEmpty()
}
catch ( GEOSException &e )
{
// looks like geometry is fubar
Q_UNUSED( e );
QgsDebugMsg( QString( "GEOS exception caught: %1" ).arg( e.what() ) );
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
return false;
}
}
Expand Down

0 comments on commit d751036

Please sign in to comment.