Skip to content

Commit 2d749be

Browse files
committed
Merge pull request #1332 from leyan/deletePart
Improve delete part feature for polygon
2 parents f9e4e78 + c0fdfcf commit 2d749be

File tree

4 files changed

+228
-138
lines changed

4 files changed

+228
-138
lines changed

src/app/qgsmaptooldeletepart.cpp

Lines changed: 102 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,20 @@
1818
#include "qgsmapcanvas.h"
1919
#include "qgsvertexmarker.h"
2020
#include "qgsvectorlayer.h"
21+
#include "qgsgeometry.h"
22+
#include "qgstolerance.h"
2123

2224
#include <QMouseEvent>
2325
#include <QMessageBox>
2426

2527
QgsMapToolDeletePart::QgsMapToolDeletePart( QgsMapCanvas* canvas )
26-
: QgsMapToolVertexEdit( canvas ), mCross( 0 )
28+
: QgsMapToolEdit( canvas ), mRubberBand( 0 )
2729
{
2830
}
2931

3032
QgsMapToolDeletePart::~QgsMapToolDeletePart()
3133
{
32-
delete mCross;
34+
delete mRubberBand;
3335
}
3436

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

4143
void QgsMapToolDeletePart::canvasPressEvent( QMouseEvent *e )
4244
{
43-
delete mCross;
44-
mCross = 0;
45+
mPressedFid = -1;
46+
mPressedPartNum = -1;
47+
delete mRubberBand;
48+
mRubberBand = 0;
4549

46-
mRecentSnappingResults.clear();
47-
//do snap -> new recent snapping results
48-
if ( mSnapper.snapToCurrentLayer( e->pos(), mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) != 0 )
50+
QgsMapLayer* currentLayer = mCanvas->currentLayer();
51+
if ( !currentLayer )
52+
return;
53+
54+
vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
55+
if ( !vlayer )
4956
{
50-
//error
57+
notifyNotVectorLayer();
58+
return;
5159
}
5260

53-
if ( mRecentSnappingResults.size() > 0 )
61+
if ( !vlayer->isEditable() )
5462
{
55-
// remove previous warning
56-
emit messageDiscarded();
63+
notifyNotEditableLayer();
64+
return;
65+
}
5766

58-
QgsPoint markerPoint = mRecentSnappingResults.begin()->snappedVertex;
67+
QgsGeometry* geomPart;
5968

60-
//show vertex marker
61-
mCross = new QgsVertexMarker( mCanvas );
62-
mCross->setIconType( QgsVertexMarker::ICON_X );
63-
mCross->setCenter( markerPoint );
64-
}
65-
else
69+
geomPart = partUnderPoint( e->pos(), mPressedFid, mPressedPartNum );
70+
71+
if ( mPressedFid != -1 )
6672
{
67-
emit messageEmitted( tr( "could not snap to a part on the current layer." ) );
73+
mRubberBand = createRubberBand( vlayer->geometryType() );
74+
75+
mRubberBand->setToGeometry( geomPart, vlayer );
76+
mRubberBand->show();
6877
}
78+
6979
}
7080

7181
void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
7282
{
7383
Q_UNUSED( e );
74-
delete mCross;
75-
mCross = 0;
7684

77-
QgsMapLayer* currentLayer = mCanvas->currentLayer();
78-
if ( !currentLayer )
79-
return;
85+
delete mRubberBand;
86+
mRubberBand = 0;
8087

81-
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
82-
if ( !vlayer )
83-
return;
84-
85-
if ( mRecentSnappingResults.size() > 0 )
88+
if ( !vlayer || !vlayer->isEditable() )
8689
{
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-
}
90+
return;
9791
}
9892

99-
}
100-
93+
if ( mPressedFid == -1 )
94+
return;
10195

102-
void QgsMapToolDeletePart::deletePart( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer )
103-
{
10496
QgsFeature f;
105-
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fId ) ).nextFeature( f );
106-
107-
// find out the part number
97+
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( mPressedFid ) ).nextFeature( f );
10898
QgsGeometry* g = f.geometry();
109-
if ( !g->isMultipart() )
110-
{
111-
QMessageBox::information( mCanvas, tr( "Delete part" ), tr( "This isn't a multipart geometry." ) );
112-
return;
113-
}
114-
115-
int partNum = partNumberOfVertex( g, beforeVertexNr );
11699

117-
if ( g->deletePart( partNum ) )
100+
if ( g->deletePart( mPressedPartNum ) )
118101
{
119102
vlayer->beginEditCommand( tr( "Part of multipart feature deleted" ) );
120-
vlayer->changeGeometry( fId, g );
103+
vlayer->changeGeometry( f.id(), g );
121104
vlayer->endEditCommand();
122105
mCanvas->refresh();
123106
}
124107
else
125108
{
126-
QMessageBox::information( mCanvas, tr( "Delete part" ), tr( "Couldn't remove the selected part." ) );
109+
emit messageEmitted( tr( "Couldn't remove the selected part." ) );
127110
}
128-
111+
return;
129112
}
130113

131-
int QgsMapToolDeletePart::partNumberOfVertex( QgsGeometry* g, int beforeVertexNr )
114+
QgsGeometry* QgsMapToolDeletePart::partUnderPoint( QPoint point, int& fid, int& partNum )
132115
{
133-
int part;
116+
QgsFeature f;
117+
QgsGeometry* geomPart = new QgsGeometry();
134118

135-
switch ( g->wkbType() )
119+
switch ( vlayer->geometryType() )
136120
{
137-
case QGis::WKBMultiPoint25D:
138-
case QGis::WKBMultiPoint:
139-
if ( beforeVertexNr < g->asMultiPoint().count() )
140-
return beforeVertexNr;
141-
else
142-
return -1;
143-
144-
case QGis::WKBMultiLineString25D:
145-
case QGis::WKBMultiLineString:
121+
case QGis::Point:
122+
case QGis::Line:
146123
{
147-
QgsMultiPolyline mline = g->asMultiPolyline();
148-
for ( part = 0; part < mline.count(); part++ )
124+
if ( mSnapper.snapToCurrentLayer( point, mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) == 0 )
149125
{
150-
if ( beforeVertexNr < mline[part].count() )
151-
return part;
152-
153-
beforeVertexNr -= mline[part].count();
126+
if ( mRecentSnappingResults.length() > 0 )
127+
{
128+
QgsSnappingResult sr = mRecentSnappingResults.first();
129+
int snapVertex = sr.snappedVertexNr;
130+
if ( snapVertex == -1 )
131+
snapVertex = sr.beforeVertexNr;
132+
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( sr.snappedAtGeometry ) ).nextFeature( f );
133+
QgsGeometry* g = f.geometry();
134+
if ( !g->isMultipart() )
135+
return geomPart;
136+
if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D )
137+
{
138+
fid = sr.snappedAtGeometry;
139+
partNum = snapVertex;
140+
return QgsGeometry::fromPoint( sr.snappedVertex );
141+
}
142+
if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D )
143+
{
144+
QgsMultiPolyline mline = g->asMultiPolyline();
145+
for ( int part = 0; part < mline.count(); part++ )
146+
{
147+
if ( snapVertex < mline[part].count() )
148+
{
149+
fid = sr.snappedAtGeometry;
150+
partNum = part;
151+
return QgsGeometry::fromPolyline( mline[part] );
152+
}
153+
snapVertex -= mline[part].count();
154+
}
155+
}
156+
}
154157
}
155-
return -1; // not found
158+
break;
156159
}
157-
158-
case QGis::WKBMultiPolygon25D:
159-
case QGis::WKBMultiPolygon:
160+
case QGis::Polygon:
160161
{
162+
QgsPoint layerCoords = toLayerCoordinates( vlayer, point );
163+
double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
164+
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
165+
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );
166+
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ) );
167+
fit.nextFeature( f );
168+
QgsGeometry* g = f.geometry();
169+
if ( !g )
170+
return geomPart;
171+
if ( !g->isMultipart() )
172+
return geomPart;
161173
QgsMultiPolygon mpolygon = g->asMultiPolygon();
162-
for ( part = 0; part < mpolygon.count(); part++ ) // go through the polygons
174+
for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons
163175
{
164176
const QgsPolygon& polygon = mpolygon[part];
165-
for ( int ring = 0; ring < polygon.count(); ring++ ) // go through the rings
177+
QgsGeometry* partGeo = QgsGeometry::fromPolygon( polygon );
178+
if ( partGeo->contains( &layerCoords ) )
166179
{
167-
if ( beforeVertexNr < polygon[ring].count() )
168-
return part;
169-
170-
beforeVertexNr -= polygon[ring].count();
180+
fid = f.id();
181+
partNum = part;
182+
return partGeo;
171183
}
172184
}
173-
return -1; // not found
185+
break;
174186
}
175-
176187
default:
177-
return -1;
188+
{
189+
break;
190+
}
178191
}
192+
return geomPart;
179193
}
180194

181-
182195
void QgsMapToolDeletePart::deactivate()
183196
{
184-
delete mCross;
185-
mCross = 0;
186-
187197
QgsMapTool::deactivate();
188198
}
189199

src/app/qgsmaptooldeletepart.h

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

19-
#include "qgsmaptoolvertexedit.h"
19+
#include "qgsmaptooledit.h"
20+
#include "qgsrubberband.h"
2021

2122
class QgsVertexMarker;
2223

2324
/**Map tool to delete vertices from line/polygon features*/
24-
class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolVertexEdit
25+
class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolEdit
2526
{
2627
Q_OBJECT
2728

@@ -39,14 +40,18 @@ class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolVertexEdit
3940
void deactivate();
4041

4142
private:
42-
QgsVertexMarker* mCross;
43+
QgsVectorLayer* vlayer;
44+
QList<QgsSnappingResult> mRecentSnappingResults;
4345

44-
//! delete part of a geometry
45-
void deletePart( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer );
46+
QgsGeometry* partUnderPoint( QPoint p, int &fid, int &partNum );
4647

47-
//! find out part number of geometry given the snapped vertex number
48-
int partNumberOfVertex( QgsGeometry* g, int beforeVertexNr );
48+
/* Rubberband that shows the part being deleted*/
49+
QgsRubberBand* mRubberBand;
4950

51+
//The feature and part where the mouse cursor was pressed
52+
//This is used to check whether we are still in the same part at cursor release
53+
int mPressedFid;
54+
int mPressedPartNum;
5055
};
5156

5257
#endif

0 commit comments

Comments
 (0)