Skip to content
Permalink
Browse files
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
  • Loading branch information
morb_au committed Jun 27, 2006
1 parent 9487036 commit adfd606ff04ec9f3e1242237eaca4ca38f94ba58
Showing with 134 additions and 24 deletions.
  1. +24 −0 src/core/qgsgeometry.cpp
  2. +9 −0 src/core/qgsgeometry.h
  3. +79 −15 src/gui/qgsmaptoolvertexedit.cpp
  4. +17 −2 src/gui/qgsmaptoolvertexedit.h
  5. +2 −5 src/gui/qgsvectorlayer.cpp
  6. +3 −2 src/gui/qgsvectorlayer.h
@@ -1316,6 +1316,30 @@ bool QgsGeometry::vertexAt(double &x, double &y,
}


double QgsGeometry::sqrDistToVertexAt(QgsPoint& point,
QgsGeometryVertexIndex& atVertex) const
{
double x;
double y;

if (vertexAt(x, y, atVertex))
{
#ifdef QGISDEBUG
std::cout << "QgsGeometry::sqrDistToVertexAt: Exiting with distance to " << x << " " << y << "." << std::endl;
#endif
return point.sqrDist(x, y);
}
else
{
#ifdef QGISDEBUG
std::cout << "QgsGeometry::sqrDistToVertexAt: Exiting with std::numeric_limits<double>::max()." << std::endl;
#endif
// probably safest to bail out with a very large number
return std::numeric_limits<double>::max();
}
}


QgsPoint QgsGeometry::closestVertexWithContext(QgsPoint& point,
QgsGeometryVertexIndex& atVertex,
double& sqrDist)
@@ -133,6 +133,15 @@ class QgsGeometry {
*/
bool vertexAt(double &x, double &y, QgsGeometryVertexIndex atVertex) const;

/**
Returns the squared cartesian distance between the given point
to the given vertex index (vertex at the given position number,
ring and item (first number is index 0))
*/
double sqrDistToVertexAt(QgsPoint& point,
QgsGeometryVertexIndex& atVertex) const;

/**
Returns, in atVertex, the closest vertex in this geometry to the given point.
The squared cartesian distance is also returned in sqrDist.
@@ -101,8 +101,9 @@ void QgsMapToolVertexEdit::canvasPressEvent(QMouseEvent * e)
//Find nearest segment of the selected line, move that node to the mouse location
if (!snapSegmentWithContext(point))
{
QMessageBox::warning(0, "Error", "Could not snap vertex. Have you set the tolerance?",
QMessageBox::Ok, Qt::NoButton);
QMessageBox::warning(0, "Error",
QObject::tr("Could not snap segment. Have you set the tolerance in Settings > Project Properties > General?"),
QMessageBox::Ok, Qt::NoButton);
return;
}

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

// Find the closest line segment to the mouse position
// Then set up the rubber band to its endpoints
// Then find the closest vertex on that line segment
// Then set up the rubber band to its adjoining vertexes

//Find nearest segment of the selected line, move that node to the mouse location
if (!snapVertexWithContext(point))
{
QMessageBox::warning(0, "Error", "Could not snap vertex. Have you set the tolerance?",
QMessageBox::Ok, Qt::NoButton);
return;
}
QgsPoint snapPoint;

snapPoint = point;
if (!snapSegmentWithContext(snapPoint))
{
QMessageBox::warning(0, "Error",
QObject::tr("Could not snap segment. Have you set the tolerance in Settings > Project Properties > General?"),
QMessageBox::Ok, Qt::NoButton);
return;
}

snapPoint = point;
if (!snapVertexOfSnappedSegment(snapPoint))
{
QMessageBox::warning(0, "Error",
QObject::tr("Could not snap vertex. Have you set the tolerance in Settings > Project Properties > General?"),
QMessageBox::Ok, Qt::NoButton);
return;
}

#ifdef QGISDEBUG
qWarning("Creating rubber band for moveVertex");
#endif

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

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

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

bool QgsMapToolVertexEdit::snapVertexOfSnappedSegment(QgsPoint& point)
{
double twoBeforeVertexSqrDist;
double beforeVertexSqrDist;

// Set up the "other side" of the snapped-to segment
QgsGeometryVertexIndex snappedTwoBeforeVertex(mSnappedBeforeVertex);
snappedTwoBeforeVertex.decrement_back();

#ifdef QGISDEBUG
std::cout << "QgsMapToolVertexEdit::snapVertexOfSnappedSegment: Choice of "
<< snappedTwoBeforeVertex.toString().toLocal8Bit().data() << " or "
<< mSnappedBeforeVertex.toString().toLocal8Bit().data() << "." << std::endl;
#endif


twoBeforeVertexSqrDist = mSnappedAtGeometry.sqrDistToVertexAt(point, snappedTwoBeforeVertex);
beforeVertexSqrDist = mSnappedAtGeometry.sqrDistToVertexAt(point, mSnappedBeforeVertex);

#ifdef QGISDEBUG
std::cout << "QgsMapToolVertexEdit::snapVertexOfSnappedSegment: Choice of "
<< twoBeforeVertexSqrDist << " or "
<< beforeVertexSqrDist << "." << std::endl;
#endif


// See which of the two verticies is closer (i.e. smaller squared distance)
if (twoBeforeVertexSqrDist < beforeVertexSqrDist)
{
mSnappedAtVertex = snappedTwoBeforeVertex;
}
else
{
mSnappedAtVertex = mSnappedBeforeVertex;
}

#ifdef QGISDEBUG
std::cout << "QgsMapToolVertexEdit::snapVertexOfSnappedSegment: Chose "
<< mSnappedAtVertex.toString().toLocal8Bit().data() << "." << std::endl;
#endif

return TRUE;
}

bool QgsMapToolVertexEdit::snapVertex(QgsPoint& point, int exclFeatureId, int exclVertexNr)
{
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mCanvas->currentLayer());
@@ -69,12 +69,27 @@ class QgsMapToolVertexEdit : public QgsMapTool
/**Searches the closest point within the project tolerance and setx mSnappedAtFeatureId and mSnappedAtVertex*/
bool snapVertexWithContext(QgsPoint& point);

/** Searches the closest vertex of "geometry" to the given "point"
This is useful when selecting a vertex to move, as the selection process is a two step process:
1. Select the closest line segment to the mouse pointer.
- snapSegmentWithContext()
2. Select the closest vertex on (1).
- snapVertexOfSnappedSegement()
Step 1 is needed to disambiguate between two geometries sharing the same vertex.
*/
bool snapVertexOfSnappedSegment(QgsPoint& point);

/**Snaps a point (without setting mSnappedAtFeatureId and mSnappedAtVertex). Does not snap to the specified vertex,
because during dragging, a vertex should not be snapped to itself*/
bool snapVertex(QgsPoint& point, int exclFeatureId, int exclVertexNr);



bool snapSegmentWithContext(QgsPoint& point);



//! The snapped-to segment before this vertex number (identifying the vertex that is being moved)
QgsGeometryVertexIndex mSnappedAtVertex;

@@ -2990,8 +2990,6 @@ QgsGeometry& snappedGeometry, double tolerance)
snappedFeatureId = feature->featureId();
snappedGeometry = *(feature->geometry());
segmentFound = true;
delete feature;
return true;
}
delete feature;
}
@@ -3018,7 +3016,6 @@ QgsGeometry& snappedGeometry, double tolerance)
snappedFeatureId = (*iter)->featureId();
snappedGeometry = *((*iter)->geometry());
segmentFound = true;
return true;
}
}

@@ -3034,10 +3031,10 @@ QgsGeometry& snappedGeometry, double tolerance)
snappedFeatureId = it->first;
snappedGeometry = it->second;
segmentFound = true;
return true;
}
}
return false;

return segmentFound;
}


@@ -380,7 +380,8 @@ public slots:
If there is no point within this tolerance, point is left unchanged.
@param tolerance The snapping tolerance
@return true if the position of point has been changed, and false otherwise */
bool snapPoint(QgsPoint& point, double tolerance);
bool snapPoint(QgsPoint& point,
double tolerance);

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

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

0 comments on commit adfd606

Please sign in to comment.