Skip to content

Commit adfd606

Browse files
author
morb_au
committed
In Vertex editing, when doing a mousedown to choose which geometry to
edit, the closest geometry will be selected (not just the first within snapping range), AND then the closest vertex *on that geometry* will be selected. This disambiguates between the same vertex shared amongst multiple geometries. git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@5550 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 9487036 commit adfd606

6 files changed

+134
-24
lines changed

src/core/qgsgeometry.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,30 @@ bool QgsGeometry::vertexAt(double &x, double &y,
13161316
}
13171317

13181318

1319+
double QgsGeometry::sqrDistToVertexAt(QgsPoint& point,
1320+
QgsGeometryVertexIndex& atVertex) const
1321+
{
1322+
double x;
1323+
double y;
1324+
1325+
if (vertexAt(x, y, atVertex))
1326+
{
1327+
#ifdef QGISDEBUG
1328+
std::cout << "QgsGeometry::sqrDistToVertexAt: Exiting with distance to " << x << " " << y << "." << std::endl;
1329+
#endif
1330+
return point.sqrDist(x, y);
1331+
}
1332+
else
1333+
{
1334+
#ifdef QGISDEBUG
1335+
std::cout << "QgsGeometry::sqrDistToVertexAt: Exiting with std::numeric_limits<double>::max()." << std::endl;
1336+
#endif
1337+
// probably safest to bail out with a very large number
1338+
return std::numeric_limits<double>::max();
1339+
}
1340+
}
1341+
1342+
13191343
QgsPoint QgsGeometry::closestVertexWithContext(QgsPoint& point,
13201344
QgsGeometryVertexIndex& atVertex,
13211345
double& sqrDist)

src/core/qgsgeometry.h

+9
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ class QgsGeometry {
133133
*/
134134
bool vertexAt(double &x, double &y, QgsGeometryVertexIndex atVertex) const;
135135

136+
/**
137+
Returns the squared cartesian distance between the given point
138+
to the given vertex index (vertex at the given position number,
139+
ring and item (first number is index 0))
140+
141+
*/
142+
double sqrDistToVertexAt(QgsPoint& point,
143+
QgsGeometryVertexIndex& atVertex) const;
144+
136145
/**
137146
Returns, in atVertex, the closest vertex in this geometry to the given point.
138147
The squared cartesian distance is also returned in sqrDist.

src/gui/qgsmaptoolvertexedit.cpp

+79-15
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ void QgsMapToolVertexEdit::canvasPressEvent(QMouseEvent * e)
101101
//Find nearest segment of the selected line, move that node to the mouse location
102102
if (!snapSegmentWithContext(point))
103103
{
104-
QMessageBox::warning(0, "Error", "Could not snap vertex. Have you set the tolerance?",
105-
QMessageBox::Ok, Qt::NoButton);
104+
QMessageBox::warning(0, "Error",
105+
QObject::tr("Could not snap segment. Have you set the tolerance in Settings > Project Properties > General?"),
106+
QMessageBox::Ok, Qt::NoButton);
106107
return;
107108
}
108109

@@ -130,15 +131,32 @@ void QgsMapToolVertexEdit::canvasPressEvent(QMouseEvent * e)
130131
#endif
131132

132133
// Find the closest line segment to the mouse position
133-
// Then set up the rubber band to its endpoints
134+
// Then find the closest vertex on that line segment
135+
// Then set up the rubber band to its adjoining vertexes
134136

135-
//Find nearest segment of the selected line, move that node to the mouse location
136-
if (!snapVertexWithContext(point))
137-
{
138-
QMessageBox::warning(0, "Error", "Could not snap vertex. Have you set the tolerance?",
139-
QMessageBox::Ok, Qt::NoButton);
140-
return;
141-
}
137+
QgsPoint snapPoint;
138+
139+
snapPoint = point;
140+
if (!snapSegmentWithContext(snapPoint))
141+
{
142+
QMessageBox::warning(0, "Error",
143+
QObject::tr("Could not snap segment. Have you set the tolerance in Settings > Project Properties > General?"),
144+
QMessageBox::Ok, Qt::NoButton);
145+
return;
146+
}
147+
148+
snapPoint = point;
149+
if (!snapVertexOfSnappedSegment(snapPoint))
150+
{
151+
QMessageBox::warning(0, "Error",
152+
QObject::tr("Could not snap vertex. Have you set the tolerance in Settings > Project Properties > General?"),
153+
QMessageBox::Ok, Qt::NoButton);
154+
return;
155+
}
156+
157+
#ifdef QGISDEBUG
158+
qWarning("Creating rubber band for moveVertex");
159+
#endif
142160

143161
index = mSnappedAtVertex;
144162
createRubberBand();
@@ -178,8 +196,9 @@ void QgsMapToolVertexEdit::canvasPressEvent(QMouseEvent * e)
178196
// TODO: Find nearest segment of the selected line, move that node to the mouse location
179197
if (!snapVertexWithContext(point))
180198
{
181-
QMessageBox::warning(0, "Error", "Could not snap vertex. Have you set the tolerance?",
182-
QMessageBox::Ok, Qt::NoButton);
199+
QMessageBox::warning(0, "Error",
200+
QObject::tr("Could not snap vertex. Have you set the tolerance in Settings > Project Properties > General?"),
201+
QMessageBox::Ok, Qt::NoButton);
183202
return;
184203
}
185204

@@ -216,14 +235,15 @@ bool QgsMapToolVertexEdit::snapSegmentWithContext(QgsPoint& point)
216235
if (!vlayer->snapSegmentWithContext(point, beforeVertex, atFeatureId, atGeometry, tolerance()))
217236
{
218237
mSnappedAtFeatureId = -1;
219-
QMessageBox::warning(0, "Error", "Could not snap segment. Have you set the tolerance?",
220-
QMessageBox::Ok, Qt::NoButton);
238+
QMessageBox::warning(0, "Error",
239+
QObject::tr("Could not snap segment. Have you set the tolerance in Settings > Project Properties > General?"),
240+
QMessageBox::Ok, Qt::NoButton);
221241
return FALSE;
222242
}
223243
else
224244
{
225245
#ifdef QGISDEBUG
226-
std::cout << "QgsMapToolVertexEdit: Snapped to segment fid " << atFeatureId << "." << std::endl;
246+
std::cout << "QgsMapToolVertexEdit::snapSegmentWithContext: Snapped to segment fid " << atFeatureId << "." << std::endl;
227247
#endif
228248

229249
// Save where we snapped to
@@ -266,6 +286,50 @@ bool QgsMapToolVertexEdit::snapVertexWithContext(QgsPoint& point)
266286
}
267287
}
268288

289+
bool QgsMapToolVertexEdit::snapVertexOfSnappedSegment(QgsPoint& point)
290+
{
291+
double twoBeforeVertexSqrDist;
292+
double beforeVertexSqrDist;
293+
294+
// Set up the "other side" of the snapped-to segment
295+
QgsGeometryVertexIndex snappedTwoBeforeVertex(mSnappedBeforeVertex);
296+
snappedTwoBeforeVertex.decrement_back();
297+
298+
#ifdef QGISDEBUG
299+
std::cout << "QgsMapToolVertexEdit::snapVertexOfSnappedSegment: Choice of "
300+
<< snappedTwoBeforeVertex.toString().toLocal8Bit().data() << " or "
301+
<< mSnappedBeforeVertex.toString().toLocal8Bit().data() << "." << std::endl;
302+
#endif
303+
304+
305+
twoBeforeVertexSqrDist = mSnappedAtGeometry.sqrDistToVertexAt(point, snappedTwoBeforeVertex);
306+
beforeVertexSqrDist = mSnappedAtGeometry.sqrDistToVertexAt(point, mSnappedBeforeVertex);
307+
308+
#ifdef QGISDEBUG
309+
std::cout << "QgsMapToolVertexEdit::snapVertexOfSnappedSegment: Choice of "
310+
<< twoBeforeVertexSqrDist << " or "
311+
<< beforeVertexSqrDist << "." << std::endl;
312+
#endif
313+
314+
315+
// See which of the two verticies is closer (i.e. smaller squared distance)
316+
if (twoBeforeVertexSqrDist < beforeVertexSqrDist)
317+
{
318+
mSnappedAtVertex = snappedTwoBeforeVertex;
319+
}
320+
else
321+
{
322+
mSnappedAtVertex = mSnappedBeforeVertex;
323+
}
324+
325+
#ifdef QGISDEBUG
326+
std::cout << "QgsMapToolVertexEdit::snapVertexOfSnappedSegment: Chose "
327+
<< mSnappedAtVertex.toString().toLocal8Bit().data() << "." << std::endl;
328+
#endif
329+
330+
return TRUE;
331+
}
332+
269333
bool QgsMapToolVertexEdit::snapVertex(QgsPoint& point, int exclFeatureId, int exclVertexNr)
270334
{
271335
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mCanvas->currentLayer());

src/gui/qgsmaptoolvertexedit.h

+17-2
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,27 @@ class QgsMapToolVertexEdit : public QgsMapTool
6969
/**Searches the closest point within the project tolerance and setx mSnappedAtFeatureId and mSnappedAtVertex*/
7070
bool snapVertexWithContext(QgsPoint& point);
7171

72+
/** Searches the closest vertex of "geometry" to the given "point"
73+
74+
This is useful when selecting a vertex to move, as the selection process is a two step process:
75+
76+
1. Select the closest line segment to the mouse pointer.
77+
- snapSegmentWithContext()
78+
2. Select the closest vertex on (1).
79+
- snapVertexOfSnappedSegement()
80+
81+
Step 1 is needed to disambiguate between two geometries sharing the same vertex.
82+
*/
83+
bool snapVertexOfSnappedSegment(QgsPoint& point);
84+
7285
/**Snaps a point (without setting mSnappedAtFeatureId and mSnappedAtVertex). Does not snap to the specified vertex,
7386
because during dragging, a vertex should not be snapped to itself*/
7487
bool snapVertex(QgsPoint& point, int exclFeatureId, int exclVertexNr);
75-
88+
89+
7690
bool snapSegmentWithContext(QgsPoint& point);
77-
91+
92+
7893
//! The snapped-to segment before this vertex number (identifying the vertex that is being moved)
7994
QgsGeometryVertexIndex mSnappedAtVertex;
8095

src/gui/qgsvectorlayer.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -2990,8 +2990,6 @@ QgsGeometry& snappedGeometry, double tolerance)
29902990
snappedFeatureId = feature->featureId();
29912991
snappedGeometry = *(feature->geometry());
29922992
segmentFound = true;
2993-
delete feature;
2994-
return true;
29952993
}
29962994
delete feature;
29972995
}
@@ -3018,7 +3016,6 @@ QgsGeometry& snappedGeometry, double tolerance)
30183016
snappedFeatureId = (*iter)->featureId();
30193017
snappedGeometry = *((*iter)->geometry());
30203018
segmentFound = true;
3021-
return true;
30223019
}
30233020
}
30243021

@@ -3034,10 +3031,10 @@ QgsGeometry& snappedGeometry, double tolerance)
30343031
snappedFeatureId = it->first;
30353032
snappedGeometry = it->second;
30363033
segmentFound = true;
3037-
return true;
30383034
}
30393035
}
3040-
return false;
3036+
3037+
return segmentFound;
30413038
}
30423039

30433040

src/gui/qgsvectorlayer.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,8 @@ public slots:
380380
If there is no point within this tolerance, point is left unchanged.
381381
@param tolerance The snapping tolerance
382382
@return true if the position of point has been changed, and false otherwise */
383-
bool snapPoint(QgsPoint& point, double tolerance);
383+
bool snapPoint(QgsPoint& point,
384+
double tolerance);
384385

385386
/**Snaps a point to the closest vertex if there is one within the snapping tolerance
386387
@param atVertex Set to a vertex index of the snapped-to vertex
@@ -401,7 +402,7 @@ public slots:
401402
QgsGeometry& snappedGeometry,
402403
double tolerance);
403404

404-
/**Snaps a point to the closest line segment if there is one within the snapping tolerance (mSnappingTolerance)
405+
/**Snaps a point to the closest line segment if there is one within the snapping tolerance ("tolerance")
405406
@param beforeVertex Set to a value where the snapped-to segment is before this vertex index
406407
@param snappedFeatureId Set to the feature ID that where the snapped-to segment belongs to.
407408
@param snappedGeometry Set to the geometry that the snapped-to segment belongs to.

0 commit comments

Comments
 (0)