Skip to content

Commit 3dbb09b

Browse files
author
jef
committedJan 12, 2010
[FEATURE] allow editing of invalid geometry in node tool
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@12749 c8812cc2-4d05-0410-92ff-de0c093fc19c

File tree

6 files changed

+473
-41
lines changed

6 files changed

+473
-41
lines changed
 

‎src/app/qgsmaptoolnodetool.cpp

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include <math.h>
2525
#include <QMouseEvent>
2626
#include <QMessageBox>
27+
#include "qgslogger.h"
28+
#include "qgisapp.h"
29+
30+
#include <QStatusBar>
2731

2832

2933
QgsRubberBand* QgsMapToolNodeTool::createRubberBandMarker( QgsPoint center, QgsVectorLayer* vlayer )
@@ -128,7 +132,7 @@ void QgsMapToolNodeTool::layerModified( bool onlyGeometry )
128132
catch ( ... )
129133
{
130134
//GEOS is throwing exception when polygon is not valid to be able to edit it
131-
//Only possibility to fix this operation sice node tool doesn't allow to strore invalid geometry after editing
135+
//Only possibility to fix this operation since node tool doesn't allow to store invalid geometry after editing
132136
mSelectionFeature->updateFromFeature();
133137
//if it does update markers just to be sure of correctness
134138
}
@@ -148,7 +152,7 @@ void QgsMapToolNodeTool::createMovingRubberBands()
148152
for ( int i = 0; i < vertexMap.size(); i++ )
149153
{
150154
//create rubber band
151-
if ( vertexMap[i].selected && !( vertexMap[i].inRubberBand ) )
155+
if ( vertexMap[i].selected && !vertexMap[i].inRubberBand )
152156
{
153157
geometry->adjacentVertices( i, beforeVertex, afterVertex );
154158
vertex = i;
@@ -774,7 +778,7 @@ void QgsMapToolNodeTool::removeRubberBands()
774778
mTopologyMovingVertexes.clear();
775779
mTopologyRubberBandVertexes.clear();
776780

777-
//remove all data from selected feature (no change to rubber bands itself
781+
//remove all data from selected feature (no change to rubber bands itself)
778782
if ( mSelectionFeature != NULL )
779783
mSelectionFeature->cleanRubberBandsData();
780784
}
@@ -936,8 +940,46 @@ void SelectionFeature::setSelectedFeature( int featureId, QgsVectorLayer* vlaye
936940
{
937941
mFeature = feature;
938942
}
943+
939944
//createvertexmap
940945
createVertexMap();
946+
947+
validateGeometry();
948+
}
949+
950+
void SelectionFeature::validateGeometry( QgsGeometry *g )
951+
{
952+
QgsDebugMsg( "validating geometry" );
953+
954+
if ( g == NULL )
955+
g = mFeature->geometry();
956+
957+
g->validateGeometry( mGeomErrors );
958+
959+
while ( !mGeomErrorMarkers.isEmpty() )
960+
{
961+
delete mGeomErrorMarkers.takeFirst();
962+
}
963+
964+
QString tip;
965+
966+
for ( int i = 0; i < mGeomErrors.size(); i++ )
967+
{
968+
tip += mGeomErrors[i].what() + "\n";
969+
if ( !mGeomErrors[i].hasWhere() )
970+
continue;
971+
972+
QgsVertexMarker *vm = createVertexMarker( mGeomErrors[i].where(), QgsVertexMarker::ICON_X );
973+
vm->setToolTip( mGeomErrors[i].what() );
974+
vm->setColor( Qt::green );
975+
vm->setZValue( vm->zValue() + 1 );
976+
mGeomErrorMarkers << vm;
977+
}
978+
979+
QStatusBar *sb = QgisApp::instance()->statusBar();
980+
sb->showMessage( QObject::tr( "%n geometry error(s) found.", "number of geometry errors", mGeomErrors.size() ) );
981+
if ( !tip.isEmpty() )
982+
sb->setToolTip( tip );
941983
}
942984

943985
void SelectionFeature::deleteSelectedVertexes()
@@ -983,7 +1025,10 @@ void SelectionFeature::deleteSelectedVertexes()
9831025
}
9841026
QgsFeature f;
9851027
mVlayer->featureAtId( mFeatureId, f, true, false );
986-
if ( !GEOSisValid( f.geometry()->asGeos() ) )
1028+
1029+
bool wasValid = false; // mGeomErrors.isEmpty();
1030+
bool isValid = GEOSisValid( f.geometry()->asGeos() );
1031+
if ( wasValid && !isValid )
9871032
{
9881033
QMessageBox::warning( NULL,
9891034
tr( "Node tool" ),
@@ -992,7 +1037,7 @@ void SelectionFeature::deleteSelectedVertexes()
9921037
QMessageBox::Ok );
9931038
}
9941039

995-
if ( count != 0 && GEOSisValid( f.geometry()->asGeos() ) )
1040+
if ( count != 0 && ( !wasValid || isValid ) )
9961041
{
9971042
mVlayer->endEditCommand();
9981043
}
@@ -1054,7 +1099,9 @@ void SelectionFeature::moveSelectedVertexes( double changeX, double changeY )
10541099
}
10551100
QgsFeature f;
10561101
mVlayer->featureAtId( mFeatureId, f, true, false );
1057-
if ( !GEOSisValid( f.geometry()->asGeos() ) )
1102+
bool wasValid = false; // mGeomErrors.isEmpty();
1103+
bool isValid = GEOSisValid( f.geometry()->asGeos() );
1104+
if ( wasValid && !isValid )
10581105
{
10591106
QMessageBox::warning( NULL,
10601107
tr( "Node tool" ),
@@ -1068,17 +1115,18 @@ void SelectionFeature::moveSelectedVertexes( double changeX, double changeY )
10681115
else
10691116
{
10701117
mVlayer->endEditCommand();
1118+
validateGeometry( f.geometry() );
10711119
}
10721120
updateFeature();
10731121
}
10741122

1075-
QgsVertexMarker* SelectionFeature::createVertexMarker( QgsPoint center )
1123+
QgsVertexMarker *SelectionFeature::createVertexMarker( QgsPoint center, QgsVertexMarker::IconType type )
10761124
{
1077-
QgsVertexMarker* marker = new QgsVertexMarker( mCanvas );
1125+
QgsVertexMarker *marker = new QgsVertexMarker( mCanvas );
10781126
QgsPoint newCenter = mCanvas->mapRenderer()->layerToMapCoordinates( mVlayer, center );
10791127
marker->setCenter( newCenter );
10801128

1081-
marker->setIconType( QgsVertexMarker::ICON_BOX );
1129+
marker->setIconType( type );
10821130

10831131
marker->setColor( Qt::red );
10841132

@@ -1103,6 +1151,11 @@ void SelectionFeature::deleteVertexMap()
11031151
VertexEntry entry = mVertexMap.takeLast();
11041152
delete entry.vertexMarker;
11051153
}
1154+
1155+
while ( !mGeomErrorMarkers.isEmpty() )
1156+
{
1157+
delete mGeomErrorMarkers.takeFirst();
1158+
}
11061159
}
11071160

11081161
bool SelectionFeature::isSelected( int vertexNr )
@@ -1134,6 +1187,7 @@ void SelectionFeature::createVertexMapPolygon()
11341187
entry.originalIndex = i;
11351188
entry.inRubberBand = false;
11361189
QgsVertexMarker* marker = createVertexMarker( poly[i] );
1190+
marker->setToolTip( tr( "ring %1, vertex %2" ).arg( i2 ).arg( i ) );
11371191
entry.vertexMarker = marker;
11381192
mVertexMap.insert( y + i, entry );
11391193
}
@@ -1161,7 +1215,7 @@ void SelectionFeature::createVertexMapPolygon()
11611215
entry.originalIndex = y + i - 1;
11621216
entry.inRubberBand = false;
11631217
QgsVertexMarker* marker = createVertexMarker( poly[i] );
1164-
1218+
marker->setToolTip( tr( "polygon %1, ring %2, vertex %3" ).arg( i2 ).arg( i3 ).arg( i ) );
11651219
entry.vertexMarker = marker;
11661220
mVertexMap.insert( y + i, entry );
11671221
}
@@ -1194,6 +1248,7 @@ void SelectionFeature::createVertexMapLine()
11941248
entry.originalIndex = i;
11951249
entry.inRubberBand = false;
11961250
QgsVertexMarker* marker = createVertexMarker( poly[i] );
1251+
marker->setToolTip( tr( "polyline %1, vertex %2" ).arg( i2 ).arg( i ) );
11971252
entry.vertexMarker = marker;
11981253
mVertexMap.insert( y + i, entry );
11991254
}
@@ -1214,6 +1269,7 @@ void SelectionFeature::createVertexMapLine()
12141269
entry.originalIndex = i;
12151270
entry.inRubberBand = false;
12161271
QgsVertexMarker* marker = createVertexMarker( poly[i] );
1272+
marker->setToolTip( tr( "vertex %1" ).arg( i ) );
12171273
entry.vertexMarker = marker;
12181274
mVertexMap.insert( i, entry );
12191275
}
@@ -1236,6 +1292,7 @@ void SelectionFeature::createVertexMapPoint()
12361292
entry.originalIndex = 1;
12371293
entry.inRubberBand = false;
12381294
QgsVertexMarker* marker = createVertexMarker( poly[i] );
1295+
marker->setToolTip( tr( "point %1" ).arg( i ) );
12391296
entry.vertexMarker = marker;
12401297
mVertexMap.insert( i, entry );
12411298
}
@@ -1251,6 +1308,7 @@ void SelectionFeature::createVertexMapPoint()
12511308
entry.originalIndex = 1;
12521309
entry.inRubberBand = false;
12531310
QgsVertexMarker* marker = createVertexMarker( poly );
1311+
marker->setToolTip( tr( "single point" ) );
12541312
entry.vertexMarker = marker;
12551313
mVertexMap.insert( 1, entry );
12561314
}
@@ -1372,4 +1430,3 @@ QgsVectorLayer* SelectionFeature::vlayer()
13721430
{
13731431
return mVlayer;
13741432
}
1375-

‎src/app/qgsmaptoolnodetool.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class SelectionFeature: public QObject
161161
* @param center center of marker
162162
* @return created vertex marker
163163
*/
164-
QgsVertexMarker* createVertexMarker( QgsPoint center );
164+
QgsVertexMarker* createVertexMarker( QgsPoint center, QgsVertexMarker::IconType type = QgsVertexMarker::ICON_BOX );
165165

166166
/**
167167
* Getter for getting vector layer which selection is working
@@ -171,7 +171,6 @@ class SelectionFeature: public QObject
171171

172172

173173
private:
174-
175174
/**
176175
* Deletes whole vertex map.
177176
*/
@@ -198,17 +197,25 @@ class SelectionFeature: public QObject
198197
void createVertexMapPoint();
199198

200199
/**
201-
* Updates stored feauture to actual one loaded from layer
200+
* Updates stored feature to actual one loaded from layer
202201
*/
203202
void updateFeature();
204203

204+
/**
205+
* Validates the geometry
206+
*/
207+
void validateGeometry( QgsGeometry *g = NULL );
208+
205209
QgsFeature* mFeature;
206210
int mFeatureId;
207211
bool mFeatureSelected;
208212
QgsVectorLayer* mVlayer;
209213
QgsRubberBand* mRubberBand;
210214
QList<VertexEntry> mVertexMap;
211215
QgsMapCanvas* mCanvas;
216+
217+
QList< QgsGeometry::Error > mGeomErrors;
218+
QList< QgsVertexMarker * > mGeomErrorMarkers;
212219
};
213220

214221
/**A maptool to move/deletes/adds vertices of line or polygon features*/
@@ -367,7 +374,6 @@ class QgsMapToolNodeTool: public QgsMapToolVertexEdit
367374

368375
/** flag to tell if edition points */
369376
bool mIsPoint;
370-
371377
};
372378

373379

‎src/core/qgsgeometry.cpp

Lines changed: 248 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,7 +2360,7 @@ double QgsGeometry::closestVertexWithContext( const QgsPoint& point, int& atVert
23602360
return -1;
23612361

23622362
const GEOSGeometry *g = GEOSGetExteriorRing( mGeos );
2363-
if ( g == NULL )
2363+
if ( !g )
23642364
return -1;
23652365

23662366
const GEOSCoordSequence *sequence = GEOSGeom_getCoordSeq( g );
@@ -5442,7 +5442,7 @@ int QgsGeometry::topologicalTestPointsSplit( const GEOSGeometry* splitLine, QLis
54425442

54435443
testPoints.clear();
54445444
GEOSGeometry* intersectionGeom = GEOSIntersection( mGeos, splitLine );
5445-
if ( intersectionGeom == NULL )
5445+
if ( !intersectionGeom )
54465446
{
54475447
return 1;
54485448
}
@@ -5853,17 +5853,17 @@ QgsMultiPolygon QgsGeometry::asMultiPolygon()
58535853

58545854
double QgsGeometry::distance( QgsGeometry& geom )
58555855
{
5856-
if ( mGeos == NULL )
5856+
if ( !mGeos )
58575857
{
58585858
exportWkbToGeos();
58595859
}
58605860

5861-
if ( geom.mGeos == NULL )
5861+
if ( !geom.mGeos )
58625862
{
58635863
geom.exportWkbToGeos();
58645864
}
58655865

5866-
if ( mGeos == NULL || geom.mGeos == NULL )
5866+
if ( !mGeos || !geom.mGeos )
58675867
return -1.0;
58685868

58695869
double dist = -1.0;
@@ -5880,7 +5880,7 @@ double QgsGeometry::distance( QgsGeometry& geom )
58805880

58815881
QgsGeometry* QgsGeometry::buffer( double distance, int segments )
58825882
{
5883-
if ( mGeos == NULL )
5883+
if ( !mGeos )
58845884
{
58855885
exportWkbToGeos();
58865886
}
@@ -5898,7 +5898,7 @@ QgsGeometry* QgsGeometry::buffer( double distance, int segments )
58985898

58995899
QgsGeometry* QgsGeometry::simplify( double tolerance )
59005900
{
5901-
if ( mGeos == NULL )
5901+
if ( !mGeos )
59025902
{
59035903
exportWkbToGeos();
59045904
}
@@ -5915,7 +5915,7 @@ QgsGeometry* QgsGeometry::simplify( double tolerance )
59155915

59165916
QgsGeometry* QgsGeometry::centroid()
59175917
{
5918-
if ( mGeos == NULL )
5918+
if ( !mGeos )
59195919
{
59205920
exportWkbToGeos();
59215921
}
@@ -5932,7 +5932,7 @@ QgsGeometry* QgsGeometry::centroid()
59325932

59335933
QgsGeometry* QgsGeometry::convexHull()
59345934
{
5935-
if ( mGeos == NULL )
5935+
if ( !mGeos )
59365936
{
59375937
exportWkbToGeos();
59385938
}
@@ -5950,15 +5950,15 @@ QgsGeometry* QgsGeometry::convexHull()
59505950

59515951
QgsGeometry* QgsGeometry::intersection( QgsGeometry* geometry )
59525952
{
5953-
if ( geometry == NULL )
5953+
if ( !geometry )
59545954
{
59555955
return NULL;
59565956
}
5957-
if ( mGeos == NULL )
5957+
if ( !mGeos )
59585958
{
59595959
exportWkbToGeos();
59605960
}
5961-
if ( geometry->mGeos == NULL )
5961+
if ( !geometry->mGeos )
59625962
{
59635963
geometry->exportWkbToGeos();
59645964
}
@@ -5976,15 +5976,15 @@ QgsGeometry* QgsGeometry::intersection( QgsGeometry* geometry )
59765976

59775977
QgsGeometry* QgsGeometry::combine( QgsGeometry* geometry )
59785978
{
5979-
if ( geometry == NULL )
5979+
if ( !geometry )
59805980
{
59815981
return NULL;
59825982
}
5983-
if ( mGeos == NULL )
5983+
if ( !mGeos )
59845984
{
59855985
exportWkbToGeos();
59865986
}
5987-
if ( geometry->mGeos == NULL )
5987+
if ( !geometry->mGeos )
59885988
{
59895989
geometry->exportWkbToGeos();
59905990
}
@@ -6015,15 +6015,15 @@ QgsGeometry* QgsGeometry::combine( QgsGeometry* geometry )
60156015

60166016
QgsGeometry* QgsGeometry::difference( QgsGeometry* geometry )
60176017
{
6018-
if ( geometry == NULL )
6018+
if ( !geometry )
60196019
{
60206020
return NULL;
60216021
}
6022-
if ( mGeos == NULL )
6022+
if ( !mGeos )
60236023
{
60246024
exportWkbToGeos();
60256025
}
6026-
if ( geometry->mGeos == NULL )
6026+
if ( !geometry->mGeos )
60276027
{
60286028
geometry->exportWkbToGeos();
60296029
}
@@ -6041,15 +6041,15 @@ QgsGeometry* QgsGeometry::difference( QgsGeometry* geometry )
60416041

60426042
QgsGeometry* QgsGeometry::symDifference( QgsGeometry* geometry )
60436043
{
6044-
if ( geometry == NULL )
6044+
if ( !geometry )
60456045
{
60466046
return NULL;
60476047
}
6048-
if ( mGeos == NULL )
6048+
if ( !mGeos )
60496049
{
60506050
exportWkbToGeos();
60516051
}
6052-
if ( geometry->mGeos == NULL )
6052+
if ( !geometry->mGeos )
60536053
{
60546054
geometry->exportWkbToGeos();
60556055
}
@@ -6067,10 +6067,10 @@ QgsGeometry* QgsGeometry::symDifference( QgsGeometry* geometry )
60676067

60686068
QList<QgsGeometry*> QgsGeometry::asGeometryCollection()
60696069
{
6070-
if ( mGeos == NULL )
6070+
if ( !mGeos )
60716071
{
60726072
exportWkbToGeos();
6073-
if ( mGeos == NULL )
6073+
if ( !mGeos )
60746074
return QList<QgsGeometry*>();
60756075
}
60766076

@@ -6258,3 +6258,228 @@ int QgsGeometry::avoidIntersections()
62586258

62596259
return returnValue;
62606260
}
6261+
6262+
//
6263+
// distance of point q from line through p in direction v
6264+
// return >0 => q lies left of the line
6265+
// <0 => q lies right of the line
6266+
//
6267+
static double distLine2Point( QgsPoint p, QgsVector v, QgsPoint q )
6268+
{
6269+
if ( v.length() == 0 )
6270+
{
6271+
throw QgsException( QObject::tr( "invalid line" ) );
6272+
}
6273+
6274+
return ( v.x()*( q.y() - p.y() ) - v.y()*( q.x() - p.x() ) ) / v.length();
6275+
}
6276+
6277+
static bool intersectLines( QgsPoint p, QgsVector v, QgsPoint q, QgsVector w, QgsPoint &s )
6278+
{
6279+
double d = v.y() * w.x() - v.x() * w.y();
6280+
6281+
if ( d == 0 )
6282+
return false;
6283+
6284+
double dx = q.x() - p.x();
6285+
double dy = q.y() - p.y();
6286+
double k = ( dy * w.x() - dx * w.y() ) / d;
6287+
6288+
s = p + v * k;
6289+
6290+
return true;
6291+
}
6292+
6293+
bool pointInRing( const QgsPolyline &ring, const QgsPoint &p )
6294+
{
6295+
bool inside = false;
6296+
int j = ring.size() - 1;
6297+
6298+
for ( int i = 0; i < ring.size(); i++ )
6299+
{
6300+
if ( ring[i].x() == p.x() && ring[i].y() == p.y() )
6301+
return true;
6302+
6303+
if (( ring[i].y() < p.y() && ring[j].y() >= p.y() ) ||
6304+
( ring[j].y() < p.y() && ring[i].y() >= p.y() ) )
6305+
{
6306+
if ( ring[i].x() + ( p.y() - ring[i].y() ) / ( ring[j].y() - ring[i].y() )*( ring[j].x() - ring[i].x() ) <= p.x() )
6307+
inside = !inside;
6308+
}
6309+
6310+
j = i;
6311+
}
6312+
6313+
return inside;
6314+
}
6315+
6316+
static bool ringInRing( const QgsPolyline &inside, const QgsPolyline &outside )
6317+
{
6318+
for ( int i = 0; i < inside.size(); i++ )
6319+
{
6320+
if ( !pointInRing( outside, inside[i] ) )
6321+
return false;
6322+
}
6323+
6324+
return true;
6325+
}
6326+
6327+
bool ringIntersectsRing( const QgsPolyline &ring0, const QgsPolyline &ring1 )
6328+
{
6329+
bool inside = false;
6330+
bool outside = false;
6331+
6332+
for ( int i = 0; i < ring0.size(); i++ )
6333+
{
6334+
if ( pointInRing( ring1, ring0[i] ) )
6335+
{
6336+
inside = true;
6337+
}
6338+
else
6339+
{
6340+
outside = true;
6341+
}
6342+
6343+
if ( outside && inside )
6344+
return true;
6345+
}
6346+
6347+
return false;
6348+
}
6349+
6350+
void QgsGeometry::validatePolyline( QList<Error> &errors, int i, const QgsPolyline &line )
6351+
{
6352+
if ( line.size() < 2 )
6353+
{
6354+
QString msg = QObject::tr( "line %1 with less than two points" ).arg( i );
6355+
QgsDebugMsg( msg );
6356+
errors << Error( msg );
6357+
return;
6358+
}
6359+
6360+
bool closed = line[0] == line[ line.size()-1 ];
6361+
6362+
if ( closed && line.size() < 3 )
6363+
{
6364+
QString msg = QObject::tr( "ring %1 with less than three points" ).arg( i );
6365+
QgsDebugMsg( msg );
6366+
errors << Error( msg );
6367+
return;
6368+
}
6369+
6370+
for ( int j = 0; j < line.size() - 3; j++ )
6371+
{
6372+
QgsVector v = line[j+1] - line[j];
6373+
6374+
int n = j == 0 && closed ? line.size() - 2 : line.size() - 1;
6375+
6376+
for ( int k = j + 2; k < n; k++ )
6377+
{
6378+
QgsVector w = line[k+1] - line[k];
6379+
6380+
QgsPoint s;
6381+
if ( intersectLines( line[j], v, line[k], w, s ) )
6382+
{
6383+
double d = -distLine2Point( line[j], v.perpVector(), s );
6384+
6385+
if ( d >= 0 && d <= v.length() )
6386+
{
6387+
d = -distLine2Point( line[k], w.perpVector(), s );
6388+
if ( d >= 0 && d <= w.length() )
6389+
{
6390+
QString msg = QObject::tr( "segments %1 and %2 of line %3 intersect at %4" ).arg( j ).arg( k ).arg( i ).arg( s.toString() );
6391+
QgsDebugMsg( msg );
6392+
errors << Error( msg, s );
6393+
if ( errors.size() > 100 )
6394+
{
6395+
QString msg = QObject::tr( "stopping validation after more than 100 errors" );
6396+
QgsDebugMsg( msg );
6397+
errors << Error( msg );
6398+
return;
6399+
}
6400+
}
6401+
}
6402+
}
6403+
}
6404+
}
6405+
}
6406+
6407+
void QgsGeometry::validatePolygon( QList<Error> &errors, int idx, const QgsPolygon &polygon )
6408+
{
6409+
for ( int i = 1; i < polygon.size(); i++ )
6410+
{
6411+
if ( !ringInRing( polygon[i], polygon[0] ) )
6412+
{
6413+
QString msg = QObject::tr( "ring %1 of polygon %2 not in exterior ring" ).arg( i ).arg( idx );
6414+
QgsDebugMsg( msg );
6415+
errors << Error( msg );
6416+
}
6417+
}
6418+
6419+
for ( int i = 1; i < polygon.size(); i++ )
6420+
{
6421+
for ( int j = i + 1; j < polygon.size(); j++ )
6422+
{
6423+
if ( ringIntersectsRing( polygon[i], polygon[j] ) )
6424+
{
6425+
QString msg = QObject::tr( "interior rings %1 and %2 of polygon %3 intersect" ).arg( i ).arg( j ).arg( idx );
6426+
QgsDebugMsg( msg );
6427+
errors << Error( msg );
6428+
}
6429+
}
6430+
}
6431+
6432+
for ( int i = 0; i < polygon.size(); i++ )
6433+
{
6434+
validatePolyline( errors, i, polygon[i] );
6435+
}
6436+
}
6437+
6438+
void QgsGeometry::validateGeometry( QList<Error> &errors )
6439+
{
6440+
errors.clear();
6441+
6442+
switch ( wkbType() )
6443+
{
6444+
case QGis::WKBPoint:
6445+
case QGis::WKBPoint25D:
6446+
case QGis::WKBMultiPoint:
6447+
case QGis::WKBMultiPoint25D:
6448+
break;
6449+
6450+
case QGis::WKBLineString:
6451+
case QGis::WKBLineString25D:
6452+
validatePolyline( errors, 0, asPolyline() );
6453+
break;
6454+
6455+
case QGis::WKBMultiLineString:
6456+
case QGis::WKBMultiLineString25D:
6457+
{
6458+
QgsMultiPolyline mp = asMultiPolyline();
6459+
for ( int i = 0; i < mp.size(); i++ )
6460+
validatePolyline( errors, i, mp[i] );
6461+
}
6462+
break;
6463+
6464+
case QGis::WKBPolygon:
6465+
case QGis::WKBPolygon25D:
6466+
{
6467+
validatePolygon( errors, 0, asPolygon() );
6468+
}
6469+
break;
6470+
6471+
case QGis::WKBMultiPolygon:
6472+
case QGis::WKBMultiPolygon25D:
6473+
{
6474+
QgsMultiPolygon mp = asMultiPolygon();
6475+
for ( int i = 0; i < mp.size(); i++ )
6476+
validatePolygon( errors, i, mp[i] );
6477+
}
6478+
break;
6479+
6480+
case QGis::WKBUnknown:
6481+
QgsDebugMsg( QObject::tr( "Unknown geometry type" ) );
6482+
errors << Error( QObject::tr( "Unknown geometry type" ) );
6483+
break;
6484+
}
6485+
}

‎src/core/qgsgeometry.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,23 @@ class CORE_EXPORT QgsGeometry
362362
*/
363363
int avoidIntersections();
364364

365+
366+
class Error
367+
{
368+
QString message;
369+
QgsPoint location;
370+
bool hasLocation;
371+
public:
372+
Error( QString m ) : message( m ), hasLocation( false ) {}
373+
Error( QString m, QgsPoint p ) : message( m ), location( p ), hasLocation( true ) {}
374+
375+
QString what() { return message; };
376+
QgsPoint where() { return location; }
377+
bool hasWhere() { return hasLocation; }
378+
};
379+
380+
void validateGeometry( QList<Error> &errors );
381+
365382
private:
366383
// Private variables
367384

@@ -494,6 +511,9 @@ class CORE_EXPORT QgsGeometry
494511
/** return polygon from wkb */
495512
QgsPolygon asPolygon( unsigned char*& ptr, bool hasZValue );
496513

514+
void validatePolyline( QList<Error> &errors, int i, const QgsPolyline &polygon );
515+
void validatePolygon( QList<Error> &errors, int i, const QgsPolygon &polygon );
516+
497517
static int refcount;
498518
}; // class QgsGeometry
499519

‎src/core/qgspoint.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,95 @@
2222
#include <QTextStream>
2323
#include <QObject> // for tr()
2424

25+
#include "qgsexception.h"
26+
27+
//
28+
// QgsVector
29+
//
30+
31+
QgsVector::QgsVector() : m_x( 0.0 ), m_y( 0.0 )
32+
{
33+
}
34+
35+
QgsVector::QgsVector( double x, double y ) : m_x( x ), m_y( y )
36+
{
37+
}
38+
39+
QgsVector QgsVector::operator-( void ) const
40+
{
41+
return QgsVector( -m_x, -m_y );
42+
}
43+
44+
QgsVector QgsVector::operator*( double scalar ) const
45+
{
46+
return QgsVector( m_x*scalar, m_y*scalar );
47+
}
48+
49+
QgsVector QgsVector::operator/( double scalar ) const
50+
{
51+
return *this * ( 1.0 / scalar );
52+
}
53+
54+
double QgsVector::operator*( QgsVector v ) const
55+
{
56+
return m_x*v.m_x + m_y*v.m_y;
57+
}
58+
59+
double QgsVector::length() const
60+
{
61+
return sqrt( m_x*m_x + m_y*m_y );
62+
}
63+
64+
double QgsVector::x() const
65+
{
66+
return m_x;
67+
}
68+
69+
double QgsVector::y() const
70+
{
71+
return m_y;
72+
}
73+
74+
// perpendicular vector (rotated 90° counter-clockwise)
75+
QgsVector QgsVector::perpVector() const
76+
{
77+
return QgsVector( -m_y, m_x );
78+
}
79+
80+
double QgsVector::angle( void ) const
81+
{
82+
double ang = atan2( m_y, m_x );
83+
return ang < 0.0 ? ang + 2.0*M_PI : ang;
84+
}
85+
86+
double QgsVector::angle( QgsVector v ) const
87+
{
88+
return v.angle() - angle();
89+
}
90+
91+
QgsVector QgsVector::rotateBy( double rot ) const
92+
{
93+
double ang = atan2( m_y, m_x ) + rot;
94+
double len = length();
95+
return QgsVector( len*cos( ang ), len*sin( ang ) );
96+
}
97+
98+
QgsVector QgsVector::normal() const
99+
{
100+
double len = length();
101+
102+
if ( len == 0.0 )
103+
{
104+
throw QgsException( "normal vector of null vector undefined" );
105+
}
106+
107+
return *this / len;
108+
}
109+
110+
111+
//
112+
// QgsPoint
113+
//
25114

26115
QgsPoint::QgsPoint( const QgsPoint& p )
27116
{

‎src/core/qgspoint.h

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,40 @@
2020
#define QGSPOINT_H
2121

2222
#include <iostream>
23-
2423
#include <QString>
2524

25+
/** \ingroup core
26+
* A class to represent a vector.
27+
* Currently no Z axis / 2.5D support is implemented.
28+
*/
29+
30+
class CORE_EXPORT QgsVector
31+
{
32+
double m_x, m_y;
33+
34+
public:
35+
QgsVector();
36+
QgsVector( double x, double y );
37+
38+
QgsVector operator-( void ) const;
39+
QgsVector operator*( double scalar ) const;
40+
QgsVector operator/( double scalar ) const;
41+
double operator*( QgsVector v ) const;
42+
double length() const;
43+
44+
double x() const;
45+
double y() const;
46+
47+
// perpendicular vector (rotated 90° counter-clockwise)
48+
QgsVector perpVector() const;
49+
50+
double angle( void ) const;
51+
double angle( QgsVector v ) const;
52+
QgsVector rotateBy( double rot ) const;
53+
QgsVector normal() const;
54+
55+
};
56+
2657
/** \ingroup core
2758
* A class to represent a point geometry.
2859
* Currently no Z axis / 2.5D support is implemented.
@@ -131,6 +162,12 @@ class CORE_EXPORT QgsPoint
131162
//! 3 if point is on open ray b.
132163
int onSegment( const QgsPoint& a, const QgsPoint& b ) const;
133164

165+
QgsVector operator-( QgsPoint p ) const { return QgsVector( m_x - p.m_x, m_y - p.m_y ); }
166+
QgsPoint &operator+=( const QgsVector &v ) { *this = *this + v; return *this; }
167+
QgsPoint &operator-=( const QgsVector &v ) { *this = *this - v; return *this; }
168+
QgsPoint operator+( const QgsVector &v ) const { return QgsPoint( m_x + v.x(), m_y + v.y() ); }
169+
QgsPoint operator-( const QgsVector &v ) const { return QgsPoint( m_x - v.x(), m_y - v.y() ); }
170+
134171
private:
135172

136173
//! x coordinate
@@ -158,6 +195,4 @@ inline std::ostream& operator << ( std::ostream& os, const QgsPoint &p )
158195
return os;
159196
}
160197

161-
162198
#endif //QGSPOINT_H
163-

0 commit comments

Comments
 (0)
Please sign in to comment.