Skip to content

Commit 609b692

Browse files
committed
Add rubberband on mouse press, code reorganisation and cleanup
1 parent 6b0796e commit 609b692

File tree

4 files changed

+199
-224
lines changed

4 files changed

+199
-224
lines changed

src/app/qgsmaptooldeletepart.cpp

Lines changed: 107 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@
1515

1616
#include "qgsmaptooldeletepart.h"
1717

18-
#include "qgisapp.h"
1918
#include "qgsmapcanvas.h"
2019
#include "qgsvertexmarker.h"
2120
#include "qgsvectorlayer.h"
22-
#include "qgsmessagebar.h"
2321
#include "qgsgeometry.h"
22+
#include "qgstolerance.h"
2423

2524
#include <QMouseEvent>
2625
#include <QMessageBox>
2726

2827
QgsMapToolDeletePart::QgsMapToolDeletePart( QgsMapCanvas* canvas )
29-
: QgsMapToolEdit( canvas )
28+
: QgsMapToolEdit( canvas ), mRubberBand( 0 )
3029
{
3130
}
3231

3332
QgsMapToolDeletePart::~QgsMapToolDeletePart()
3433
{
34+
delete mRubberBand;
3535
}
3636

3737
void QgsMapToolDeletePart::canvasMoveEvent( QMouseEvent *e )
@@ -42,18 +42,10 @@ void QgsMapToolDeletePart::canvasMoveEvent( QMouseEvent *e )
4242

4343
void QgsMapToolDeletePart::canvasPressEvent( QMouseEvent *e )
4444
{
45-
46-
mRecentSnappingResults.clear();
47-
//do snap -> new recent snapping results
48-
if ( mSnapper.snapToCurrentLayer( e->pos(), mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) != 0 )
49-
{
50-
//error
51-
}
52-
}
53-
54-
void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
55-
{
56-
Q_UNUSED( e );
45+
mPressedFid = -1;
46+
mPressedPartNum = -1;
47+
delete mRubberBand;
48+
mRubberBand = 0;
5749

5850
QgsMapLayer* currentLayer = mCanvas->currentLayer();
5951
if ( !currentLayer )
@@ -71,62 +63,48 @@ void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
7163
notifyNotEditableLayer();
7264
return;
7365
}
74-
QgsGeometry* g;
75-
QgsFeature f;
76-
int partNum;
77-
switch( vlayer->geometryType() )
66+
67+
QgsGeometry* geomPart;
68+
69+
geomPart = partUnderPoint( e->pos(), mPressedFid, mPressedPartNum );
70+
71+
if ( mPressedFid != -1 )
7872
{
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->wkbType() == QGis::WKBPoint25D || g->wkbType() == QGis::WKBPoint ||
92-
g->wkbType() == QGis::WKBLineString25D || g->wkbType() == QGis::WKBLineString)
93-
{
94-
emit messageEmitted( tr( "The Delete part tool cannot be used on single part features." ) );
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;
73+
mRubberBand = createRubberBand( vlayer->geometryType() );
11374

114-
if ( g->wkbType() == QGis::WKBPolygon25D || g->wkbType() == QGis::WKBPolygon)
115-
{
116-
emit messageEmitted( tr( "The Delete part tool cannot be used on single part features." ) );
117-
return;
118-
}
119-
partNum = partNumberOfPoint( g, p );
120-
if ( partNum < 0 )
121-
return;
122-
break;
123-
}
124-
default:
125-
{
126-
QgsDebugMsg("Unknown geometry type");
127-
return;
128-
}
75+
mRubberBand->setToGeometry( geomPart, vlayer );
76+
mRubberBand->setColor( QColor( 255, 0, 0, 65 ) );
77+
mRubberBand->setWidth( 2 );
78+
mRubberBand->show();
79+
}
80+
81+
}
82+
83+
void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
84+
{
85+
86+
delete mRubberBand;
87+
mRubberBand = 0;
88+
89+
if ( !vlayer || !vlayer->isEditable() )
90+
{
91+
return;
12992
}
93+
94+
if ( mPressedFid == -1 )
95+
return;
96+
97+
int fid;
98+
int partNum;
99+
partUnderPoint( e->pos(), fid, partNum );
100+
101+
if ( fid != mPressedFid || partNum != mPressedPartNum )
102+
return;
103+
104+
QgsFeature f;
105+
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) ).nextFeature( f );
106+
QgsGeometry* g = f.geometry();
107+
130108
if ( g->deletePart( partNum ) )
131109
{
132110
vlayer->beginEditCommand( tr( "Part of multipart feature deleted" ) );
@@ -141,113 +119,89 @@ void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
141119
return;
142120
}
143121

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

186-
switch ( g->wkbType() )
127+
switch ( vlayer->geometryType() )
187128
{
188-
case QGis::WKBLineString25D:
189-
case QGis::WKBLineString:
190-
case QGis::WKBPoint25D:
191-
case QGis::WKBPoint:
192-
case QGis::WKBPolygon25D:
193-
case QGis::WKBPolygon:
194-
return 1;
195-
196-
case QGis::WKBMultiPoint25D:
197-
case QGis::WKBMultiPoint:
198-
if ( beforeVertexNr < g->asMultiPoint().count() )
199-
return beforeVertexNr;
200-
else
201-
return -1;
202-
203-
case QGis::WKBMultiLineString25D:
204-
case QGis::WKBMultiLineString:
129+
case QGis::Point:
130+
case QGis::Line:
205131
{
206-
QgsMultiPolyline mline = g->asMultiPolyline();
207-
for ( part = 0; part < mline.count(); part++ )
132+
if ( mSnapper.snapToCurrentLayer( point, mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) == 0 )
208133
{
209-
if ( beforeVertexNr < mline[part].count() )
210-
return part;
211-
212-
beforeVertexNr -= mline[part].count();
134+
if ( mRecentSnappingResults.length() > 0 )
135+
{
136+
QgsSnappingResult sr = mRecentSnappingResults.first();
137+
int snapVertex = sr.snappedVertexNr;
138+
if ( snapVertex == -1 )
139+
snapVertex = sr.beforeVertexNr;
140+
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( sr.snappedAtGeometry ) ).nextFeature( f );
141+
QgsGeometry* g = f.geometry();
142+
if ( !g->isMultipart() )
143+
return geomPart;
144+
if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D )
145+
{
146+
fid = sr.snappedAtGeometry;
147+
partNum = snapVertex;
148+
return QgsGeometry::fromPoint( sr.snappedVertex );
149+
}
150+
if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D )
151+
{
152+
QgsMultiPolyline mline = g->asMultiPolyline();
153+
for ( int part = 0; part < mline.count(); part++ )
154+
{
155+
if ( snapVertex < mline[part].count() )
156+
{
157+
fid = sr.snappedAtGeometry;
158+
partNum = part;
159+
return QgsGeometry::fromPolyline( mline[part] );
160+
}
161+
snapVertex -= mline[part].count();
162+
}
163+
}
164+
}
213165
}
214-
return -1; // not found
166+
break;
215167
}
216-
217-
case QGis::WKBMultiPolygon25D:
218-
case QGis::WKBMultiPolygon:
168+
case QGis::Polygon:
219169
{
170+
QgsPoint layerCoords = toLayerCoordinates( vlayer, point );
171+
double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
172+
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
173+
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );
174+
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ) );
175+
fit.nextFeature( f );
176+
QgsGeometry* g = f.geometry();
177+
if ( !g )
178+
return geomPart;
179+
if ( !g->isMultipart() )
180+
return geomPart;
220181
QgsMultiPolygon mpolygon = g->asMultiPolygon();
221-
for ( part = 0; part < mpolygon.count(); part++ ) // go through the polygons
182+
for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons
222183
{
223184
const QgsPolygon& polygon = mpolygon[part];
224-
for ( int ring = 0; ring < polygon.count(); ring++ ) // go through the rings
185+
QgsGeometry* partGeo = QgsGeometry::fromPolygon( polygon );
186+
if ( partGeo->contains( &layerCoords ) )
225187
{
226-
if ( beforeVertexNr < polygon[ring].count() )
227-
return part;
228-
229-
beforeVertexNr -= polygon[ring].count();
188+
fid = f.id();
189+
partNum = part;
190+
return partGeo;
230191
}
231192
}
232-
return -1; // not found
193+
break;
233194
}
234-
235195
default:
236-
return -1;
196+
{
197+
break;
198+
}
237199
}
200+
return geomPart;
238201
}
239202

240203
void QgsMapToolDeletePart::deactivate()
241204
{
242205
QgsMapTool::deactivate();
243206
}
244207

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

src/app/qgsmaptooldeletepart.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define QGSMAPTOOLDELETEPART_H
1818

1919
#include "qgsmaptooledit.h"
20+
#include "qgsrubberband.h"
2021

2122
class QgsVertexMarker;
2223

@@ -42,17 +43,15 @@ class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolEdit
4243
QgsVectorLayer* vlayer;
4344
QList<QgsSnappingResult> mRecentSnappingResults;
4445

45-
//! find out the part number of geometry given the vertex number
46-
int partNumberOfVertex( QgsGeometry* g, int beforeVertexNr );
46+
QgsGeometry* partUnderPoint( QPoint p, int &fid, int &partNum );
4747

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();
48+
/* Rubberband that shows the part being deleted*/
49+
QgsRubberBand* mRubberBand;
5550

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;
5655
};
5756

5857
#endif

0 commit comments

Comments
 (0)