Skip to content

Commit 717ef84

Browse files
committedApr 29, 2014
Improve delete part feature to allow deletion by clicking inside a polygon part
1 parent dd739ef commit 717ef84

File tree

2 files changed

+137
-64
lines changed

2 files changed

+137
-64
lines changed
 

‎src/app/qgsmaptooldeletepart.cpp

Lines changed: 124 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,23 @@
1515

1616
#include "qgsmaptooldeletepart.h"
1717

18+
#include "qgisapp.h"
1819
#include "qgsmapcanvas.h"
1920
#include "qgsvertexmarker.h"
2021
#include "qgsvectorlayer.h"
22+
#include "qgsmessagebar.h"
23+
#include "qgsgeometry.h"
2124

2225
#include <QMouseEvent>
2326
#include <QMessageBox>
2427

2528
QgsMapToolDeletePart::QgsMapToolDeletePart( QgsMapCanvas* canvas )
26-
: QgsMapToolVertexEdit( canvas ), mCross( 0 )
29+
: QgsMapToolEdit( canvas ), mCross( 0 )
2730
{
2831
}
2932

3033
QgsMapToolDeletePart::~QgsMapToolDeletePart()
3134
{
32-
delete mCross;
3335
}
3436

3537
void QgsMapToolDeletePart::canvasMoveEvent( QMouseEvent *e )
@@ -40,92 +42,144 @@ void QgsMapToolDeletePart::canvasMoveEvent( QMouseEvent *e )
4042

4143
void QgsMapToolDeletePart::canvasPressEvent( QMouseEvent *e )
4244
{
43-
delete mCross;
44-
mCross = 0;
4545

4646
mRecentSnappingResults.clear();
4747
//do snap -> new recent snapping results
4848
if ( mSnapper.snapToCurrentLayer( e->pos(), mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) != 0 )
4949
{
5050
//error
5151
}
52-
53-
if ( mRecentSnappingResults.size() > 0 )
54-
{
55-
// remove previous warning
56-
emit messageDiscarded();
57-
58-
QgsPoint markerPoint = mRecentSnappingResults.begin()->snappedVertex;
59-
60-
//show vertex marker
61-
mCross = new QgsVertexMarker( mCanvas );
62-
mCross->setIconType( QgsVertexMarker::ICON_X );
63-
mCross->setCenter( markerPoint );
64-
}
65-
else
66-
{
67-
emit messageEmitted( tr( "could not snap to a part on the current layer." ) );
68-
}
6952
}
7053

7154
void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
7255
{
7356
Q_UNUSED( e );
74-
delete mCross;
75-
mCross = 0;
7657

7758
QgsMapLayer* currentLayer = mCanvas->currentLayer();
7859
if ( !currentLayer )
7960
return;
8061

81-
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
62+
vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
8263
if ( !vlayer )
64+
{
65+
notifyNotVectorLayer();
8366
return;
67+
}
8468

85-
if ( mRecentSnappingResults.size() > 0 )
69+
if ( !vlayer->isEditable() )
8670
{
87-
QList<QgsSnappingResult>::iterator sr_it = mRecentSnappingResults.begin();
88-
for ( ; sr_it != mRecentSnappingResults.end(); ++sr_it )
89-
{
90-
if ( sr_it->snappedVertexNr != -1 )
91-
deletePart( sr_it->snappedAtGeometry, sr_it->snappedVertexNr, vlayer );
92-
else if ( sr_it->beforeVertexNr != -1 )
93-
deletePart( sr_it->snappedAtGeometry, sr_it->beforeVertexNr, vlayer );
94-
else if ( sr_it->afterVertexNr != -1 )
95-
deletePart( sr_it->snappedAtGeometry, sr_it->afterVertexNr, vlayer );
96-
}
71+
notifyNotEditableLayer();
72+
return;
9773
}
98-
99-
}
100-
101-
102-
void QgsMapToolDeletePart::deletePart( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer )
103-
{
74+
QgsGeometry* g;
10475
QgsFeature f;
105-
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fId ) ).nextFeature( f );
106-
107-
// find out the part number
108-
QgsGeometry* g = f.geometry();
109-
if ( !g->isMultipart() )
76+
int partNum;
77+
switch( vlayer->geometryType() )
11078
{
111-
QMessageBox::information( mCanvas, tr( "Delete part" ), tr( "This isn't a multipart geometry." ) );
112-
return;
79+
case QGis::Point:
80+
case QGis::Line:
81+
{
82+
if ( mRecentSnappingResults.size() == 0 )
83+
{
84+
return;
85+
}
86+
QgsSnappingResult sr = mRecentSnappingResults.first();
87+
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( sr.snappedAtGeometry ) ).nextFeature( f );
88+
g = f.geometry();
89+
if ( !g )
90+
return;
91+
if ( ( g->type() == QGis::Point && g->asMultiPoint().size() == 1) ||
92+
( g->type() == QGis::Line && g->asMultiPolyline().size() == 1 ) )
93+
{
94+
notifySinglePart();
95+
return;
96+
}
97+
int vertex = sr.snappedVertexNr;
98+
if ( vertex == -1 )
99+
{
100+
vertex = sr.beforeVertexNr;
101+
}
102+
partNum = partNumberOfVertex( g, vertex );
103+
break;
104+
}
105+
case QGis::Polygon:
106+
{
107+
QgsPoint p = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(),e->y());
108+
p = toLayerCoordinates(vlayer, p);
109+
f = featureUnderPoint(p);
110+
g = f.geometry();
111+
if ( !g )
112+
return;
113+
if ( g->asMultiPolygon().size() == 1 )
114+
{
115+
notifySinglePart();
116+
return;
117+
}
118+
partNum = partNumberOfPoint( g, p );
119+
if ( partNum < 0 )
120+
return;
121+
break;
122+
}
123+
default:
124+
{
125+
QgsDebugMsg("Unknown geometry type");
126+
return;
127+
}
113128
}
114-
115-
int partNum = partNumberOfVertex( g, beforeVertexNr );
116-
117129
if ( g->deletePart( partNum ) )
118130
{
119131
vlayer->beginEditCommand( tr( "Part of multipart feature deleted" ) );
120-
vlayer->changeGeometry( fId, g );
132+
vlayer->changeGeometry( f.id(), g );
121133
vlayer->endEditCommand();
122134
mCanvas->refresh();
123135
}
124136
else
125137
{
126-
QMessageBox::information( mCanvas, tr( "Delete part" ), tr( "Couldn't remove the selected part." ) );
138+
QgisApp::instance()->messageBar()->pushMessage(
139+
tr( "Delete part" ),
140+
tr( "Couldn't remove the selected part." ),
141+
QgsMessageBar::WARNING,
142+
QgisApp::instance()->messageTimeout() );
127143
}
144+
return;
145+
}
128146

147+
QgsFeature QgsMapToolDeletePart::featureUnderPoint(QgsPoint p)
148+
{
149+
QgsRectangle r;
150+
double searchRadius = mCanvas->extent().width()/100;
151+
r.setXMinimum( p.x() - searchRadius );
152+
r.setXMaximum( p.x() + searchRadius );
153+
r.setYMinimum( p.y() - searchRadius );
154+
r.setYMaximum( p.y() + searchRadius );
155+
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( r ) );
156+
QgsFeature f;
157+
fit.nextFeature( f );
158+
return f;
159+
}
160+
161+
162+
int QgsMapToolDeletePart::partNumberOfPoint(QgsGeometry *g, QgsPoint point)
163+
{
164+
int part;
165+
switch ( g->wkbType() )
166+
{
167+
case QGis::WKBMultiPolygon25D:
168+
case QGis::WKBMultiPolygon:
169+
{
170+
QgsMultiPolygon mpolygon = g->asMultiPolygon();
171+
for ( part = 0; part < mpolygon.count(); part++ ) // go through the polygons
172+
{
173+
const QgsPolygon& polygon = mpolygon[part];
174+
QgsGeometry* partGeo = QgsGeometry::fromPolygon(polygon);
175+
if ( partGeo->contains( &point ) )
176+
return part;
177+
}
178+
return -1; // not found
179+
}
180+
default:
181+
return -1;
182+
}
129183
}
130184

131185
int QgsMapToolDeletePart::partNumberOfVertex( QgsGeometry* g, int beforeVertexNr )
@@ -134,6 +188,14 @@ int QgsMapToolDeletePart::partNumberOfVertex( QgsGeometry* g, int beforeVertexNr
134188

135189
switch ( g->wkbType() )
136190
{
191+
case QGis::WKBLineString25D:
192+
case QGis::WKBLineString:
193+
case QGis::WKBPoint25D:
194+
case QGis::WKBPoint:
195+
case QGis::WKBPolygon25D:
196+
case QGis::WKBPolygon:
197+
return 1;
198+
137199
case QGis::WKBMultiPoint25D:
138200
case QGis::WKBMultiPoint:
139201
if ( beforeVertexNr < g->asMultiPoint().count() )
@@ -178,12 +240,17 @@ int QgsMapToolDeletePart::partNumberOfVertex( QgsGeometry* g, int beforeVertexNr
178240
}
179241
}
180242

181-
182243
void QgsMapToolDeletePart::deactivate()
183244
{
184-
delete mCross;
185-
mCross = 0;
186-
187245
QgsMapTool::deactivate();
188246
}
189247

248+
void QgsMapToolDeletePart::notifySinglePart()
249+
{
250+
QgisApp::instance()->messageBar()->pushMessage(
251+
tr( "Cannot use delete part" ),
252+
tr( "The Delete part tool cannot be used on single part features." ),
253+
QgsMessageBar::INFO,
254+
QgisApp::instance()->messageTimeout() );
255+
return;
256+
}

‎src/app/qgsmaptooldeletepart.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
#ifndef QGSMAPTOOLDELETEPART_H
1717
#define QGSMAPTOOLDELETEPART_H
1818

19-
#include "qgsmaptoolvertexedit.h"
19+
#include "qgsmaptooledit.h"
2020

2121
class QgsVertexMarker;
2222

2323
/**Map tool to delete vertices from line/polygon features*/
24-
class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolVertexEdit
24+
class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolEdit
2525
{
2626
Q_OBJECT
2727

@@ -39,14 +39,20 @@ class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolVertexEdit
3939
void deactivate();
4040

4141
private:
42-
QgsVertexMarker* mCross;
42+
QgsVectorLayer* vlayer;
43+
QList<QgsSnappingResult> mRecentSnappingResults;
4344

44-
//! delete part of a geometry
45-
void deletePart( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer );
46-
47-
//! find out part number of geometry given the snapped vertex number
45+
//! find out the part number of geometry given the vertex number
4846
int partNumberOfVertex( QgsGeometry* g, int beforeVertexNr );
4947

48+
//! find out the part number of geometry including the point
49+
int partNumberOfPoint( QgsGeometry* g, QgsPoint point );
50+
51+
//! find which feature is under the point position (different from snapping as we allow the whole polygon surface)
52+
QgsFeature featureUnderPoint(QgsPoint p);
53+
54+
void notifySinglePart();
55+
5056
};
5157

5258
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.