Skip to content

Commit

Permalink
node tool fixes:
Browse files Browse the repository at this point in the history
- fix OTFR support (fixes #5327.16)
- smaller snap tolerance for geographic CRSs (fixes #5661)
- use different snapping epsilons in QgsVectorLayer::snapToGeometry() for
  layers with geographic and projected crs.
- [API] enhancements (to fix #5661):
 * QgsGeometry::closestSegmentWithContext: allow passing of segment snapping
   epsilon
 * QgsPoint::sqrDistToSegment: allow assing of segment snapping epsilon
 * QgsMapLayer::crs() add "const"
  • Loading branch information
jef-n committed May 29, 2012
1 parent f97b043 commit b870b55
Show file tree
Hide file tree
Showing 11 changed files with 57 additions and 66 deletions.
79 changes: 34 additions & 45 deletions src/app/nodetool/qgsmaptoolnodetool.cpp
Expand Up @@ -249,6 +249,7 @@ void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
}
}
createMovingRubberBands();

QList<QgsSnappingResult> snapResults;
QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );
mPosMapCoordBackup = posMapCoord;
Expand All @@ -257,26 +258,29 @@ void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
{
// move rubberband
QList<QgsSnappingResult> snapResults;
QgsPoint firstCoords = toMapCoordinates( mPressCoordinates );
QList<QgsPoint> excludePoints;
excludePoints.append( mClosestVertex );
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, excludePoints );
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, QList<QgsPoint>() << mClosestMapVertex );

// get correct coordinates to move to
QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );

QgsPoint pressMapCoords;
if ( snapResults.size() > 0 )
{
firstCoords = toMapCoordinates( vlayer, mClosestVertex );
pressMapCoords = mClosestMapVertex;
}
else
{
pressMapCoords = toMapCoordinates( mPressCoordinates );
}

QgsVector offset = posMapCoord - pressMapCoords;

// handle points
if ( mIsPoint )
{
double offsetX = posMapCoord.x() - firstCoords.x();
double offsetY = posMapCoord.y() - firstCoords.y();
for ( int i = 0; i < mRubberBands.size(); i++ )
{
mRubberBands[i]->setTranslationOffset( offsetX, offsetY );
mRubberBands[i]->setTranslationOffset( offset.x(), offset.y() );
}
return;
}
Expand All @@ -285,25 +289,21 @@ void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{
if ( !vertexMap[i]->isSelected() )
continue;

if ( vertexMap[i]->isSelected() )
{
QgsPoint mapCoords = toMapCoordinates( vlayer, vertexMap[i]->point() );
double x = mapCoords.x() + posMapCoord.x() - firstCoords.x();
double y = mapCoords.y() + posMapCoord.y() - firstCoords.y();
QgsPoint p = toMapCoordinates( vlayer, vertexMap[i]->point() ) + offset;

mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( vertexMap[i]->rubberBandIndex(), QgsPoint( x, y ) );
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( vertexMap[i]->rubberBandIndex(), p );

if ( vertexMap[i]->rubberBandIndex() == 0 )
{
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( 0, QgsPoint( x, y ) );
}
if ( vertexMap[i]->rubberBandIndex() == 0 )
{
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( 0, p );
}
}

// topological editing
double offsetX = posMapCoord.x() - mPosMapCoordBackup.x();
double offsetY = posMapCoord.y() - mPosMapCoordBackup.y();
offset = posMapCoord - mPosMapCoordBackup;
for ( int i = 0; i < mTopologyRubberBand.size(); i++ )
{
for ( int pointIndex = 0; pointIndex < mTopologyRubberBand[i]->numberOfVertices() - 1; pointIndex++ )
Expand All @@ -315,10 +315,10 @@ void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
{
break;
}
mTopologyRubberBand[i]->movePoint( pointIndex, QgsPoint( point->x() + offsetX, point->y() + offsetY ) );
mTopologyRubberBand[i]->movePoint( pointIndex, *point + offset );
if ( pointIndex == 0 )
{
mTopologyRubberBand[i]->movePoint( pointIndex , QgsPoint( point->x() + offsetX, point->y() + offsetY ) );
mTopologyRubberBand[i]->movePoint( pointIndex, *point + offset );
}
}
}
Expand Down Expand Up @@ -370,22 +370,22 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
else
{
// some feature already selected
QgsPoint mapCoordPoint = toMapCoordinates( e->pos() );
QgsPoint layerCoordPoint = toLayerCoordinates( vlayer, e->pos() );

double tol = QgsTolerance::vertexSearchRadius( vlayer, mCanvas->mapRenderer() );

// get geometry and find if snapping is near it
int atVertex, beforeVertex, afterVertex;
double dist;
mSelectedFeature->geometry()->closestVertex( toLayerCoordinates( vlayer, mapCoordPoint ), atVertex, beforeVertex, afterVertex, dist );
QgsPoint closestLayerVertex = mSelectedFeature->geometry()->closestVertex( layerCoordPoint, atVertex, beforeVertex, afterVertex, dist );
dist = sqrt( dist );

mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex, tol );
if ( dist <= tol )
{
// some vertex selected
mMoving = true;
QgsPoint point = toMapCoordinates( e->pos() );
mClosestVertex = closestVertex( toLayerCoordinates( vlayer, point ) );
mClosestMapVertex = toMapCoordinates( vlayer, closestLayerVertex );
if ( mMoving )
{
if ( mSelectedFeature->isSelected( atVertex ) )
Expand Down Expand Up @@ -437,8 +437,7 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
if ( !mSelectAnother )
{
mMoving = true;
QgsPoint point = toMapCoordinates( e->pos() );
mClosestVertex = closestVertex( toLayerCoordinates( vlayer, point ) );
mClosestMapVertex = toMapCoordinates( vlayer, closestLayerVertex );

if ( mIsPoint )
{
Expand Down Expand Up @@ -519,14 +518,14 @@ void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
mMoving = false;

QList<QgsSnappingResult> snapResults;
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, QList<QgsPoint>() << mClosestVertex );
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, QList<QgsPoint>() << mClosestMapVertex );

QgsPoint releaseCoords = snapPointFromResults( snapResults, e->pos() );
QgsPoint pressCoords;
QgsPoint releaseLayerCoords = toLayerCoordinates( vlayer, snapPointFromResults( snapResults, e->pos() ) );

QgsPoint pressLayerCoords;
if ( snapResults.size() > 0 )
{
pressCoords = toLayerCoordinates( vlayer, mClosestVertex );
pressLayerCoords = toLayerCoordinates( vlayer, mClosestMapVertex );

int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
if ( topologicalEditing )
Expand All @@ -536,10 +535,10 @@ void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
}
else
{
pressCoords = toLayerCoordinates( vlayer, mPressCoordinates );
pressLayerCoords = toLayerCoordinates( vlayer, mPressCoordinates );
}

mSelectedFeature->moveSelectedVertexes( releaseCoords - pressCoords );
mSelectedFeature->moveSelectedVertexes( releaseLayerCoords - pressLayerCoords );
mCanvas->refresh();
}
else // selecting vertexes by rubberband
Expand Down Expand Up @@ -645,8 +644,7 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
return;

// some segment selected
QgsPoint coords = snapResults.first().snappedVertex;
QgsPoint layerCoords = toLayerCoordinates( vlayer, coords );
QgsPoint layerCoords = toLayerCoordinates( vlayer, snapResults.first().snappedVertex );
if ( topologicalEditing )
{
// snap from adding position to this vertex when topological editing is enabled
Expand Down Expand Up @@ -677,15 +675,6 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
mCanvas->refresh();
}

QgsPoint QgsMapToolNodeTool::closestVertex( QgsPoint point )
{
int at;
int before;
int after;
double dist;
return mSelectedFeature->geometry()->closestVertex( point, at, before, after, dist );
}

void QgsMapToolNodeTool::keyPressEvent( QKeyEvent* e )
{
if ( e->key() == Qt::Key_Control )
Expand Down
9 changes: 2 additions & 7 deletions src/app/nodetool/qgsmaptoolnodetool.h
Expand Up @@ -52,11 +52,6 @@ class QgsMapToolNodeTool: public QgsMapToolVertexEdit
//! called when map tool is being deactivated
void deactivate();

/**
* Returns closest vertex to given point from selected feature
*/
QgsPoint closestVertex( QgsPoint point );

public slots:
void selectedFeatureDestroyed();

Expand Down Expand Up @@ -134,8 +129,8 @@ class QgsMapToolNodeTool: public QgsMapToolVertexEdit
/** stored position of last press down action to count how much vertexes should be moved */
QPoint mPressCoordinates;

/** closest vertex to click */
QgsPoint mClosestVertex;
/** closest vertex to click in map coordinates */
QgsPoint mClosestMapVertex;

/** backup of map coordinates to be able to count change between moves */
QgsPoint mPosMapCoordBackup;
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgis.h
Expand Up @@ -186,6 +186,9 @@ const double MINIMUM_POINT_SIZE = 0.1;
const double DEFAULT_POINT_SIZE = 2.0;
const double DEFAULT_LINE_WIDTH = 0.26;

/** default snapping tolerance for segments (@note added in 1.8) */
const double DEFAULT_SEGMENT_EPSILON = 1e-8;

// FIXME: also in qgisinterface.h
#ifndef QGISEXTERN
#ifdef WIN32
Expand Down
11 changes: 6 additions & 5 deletions src/core/qgsgeometry.cpp
Expand Up @@ -2409,7 +2409,8 @@ double QgsGeometry::closestSegmentWithContext(
const QgsPoint& point,
QgsPoint& minDistPoint,
int& afterVertex,
double* leftOf )
double* leftOf,
double epsilon )
{
QgsDebugMsg( "Entering." );
QgsPoint distPoint;
Expand Down Expand Up @@ -2470,7 +2471,7 @@ double QgsGeometry::closestSegmentWithContext(

if ( index > 0 )
{
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint ) ) < sqrDist )
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist )
{
closestSegmentIndex = index;
sqrDist = testdist;
Expand Down Expand Up @@ -2518,7 +2519,7 @@ double QgsGeometry::closestSegmentWithContext(
}
if ( prevx && prevy )
{
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint ) ) < sqrDist )
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist )
{
closestSegmentIndex = pointindex;
sqrDist = testdist;
Expand Down Expand Up @@ -2564,7 +2565,7 @@ double QgsGeometry::closestSegmentWithContext(
}
if ( prevx && prevy )
{
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint ) ) < sqrDist )
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist )
{
closestSegmentIndex = index;
sqrDist = testdist;
Expand Down Expand Up @@ -2616,7 +2617,7 @@ double QgsGeometry::closestSegmentWithContext(
}
if ( prevx && prevy )
{
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint ) ) < sqrDist )
if (( testdist = point.sqrDistToSegment( *prevx, *prevy, *thisx, *thisy, distPoint, epsilon ) ) < sqrDist )
{
closestSegmentIndex = pointindex;
sqrDist = testdist;
Expand Down
3 changes: 2 additions & 1 deletion src/core/qgsgeometry.h
Expand Up @@ -242,9 +242,10 @@ class CORE_EXPORT QgsGeometry
* @param afterVertex Receives index of the vertex after the closest segment. The vertex
* before the closest segment is always afterVertex - 1
* @param leftOf Out: Returns if the point lies on the left of right side of the segment ( < 0 means left, > 0 means right )
* @param epsilon epsilon for segment snapping (added in 1.8)
* @return The squared cartesian distance is also returned in sqrDist, negative number on error
*/
double closestSegmentWithContext( const QgsPoint& point, QgsPoint& minDistPoint, int& afterVertex, double* leftOf = 0 );
double closestSegmentWithContext( const QgsPoint& point, QgsPoint& minDistPoint, int& afterVertex, double* leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON );

/**Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
@return 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsmaplayer.cpp
Expand Up @@ -498,7 +498,7 @@ void QgsMapLayer::setSubLayerVisibility( QString name, bool vis )
// NOOP
}

const QgsCoordinateReferenceSystem& QgsMapLayer::crs()
const QgsCoordinateReferenceSystem& QgsMapLayer::crs() const
{
return *mCRS;
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsmaplayer.h
Expand Up @@ -221,7 +221,7 @@ class CORE_EXPORT QgsMapLayer : public QObject
/** Returns layer's spatial reference system
@note This was introduced in QGIS 1.4
*/
const QgsCoordinateReferenceSystem& crs();
const QgsCoordinateReferenceSystem& crs() const;

/** Returns layer's spatial reference system
@note This method is here for API compatibility
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgspoint.cpp
Expand Up @@ -245,7 +245,7 @@ int QgsPoint::onSegment( const QgsPoint& a, const QgsPoint& b ) const
return 2;
}

double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint ) const
double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint, double epsilon ) const
{
double nx, ny; //normal vector

Expand Down Expand Up @@ -273,7 +273,7 @@ double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, Q

double dist = sqrDist( minDistPoint );
//prevent rounding errors if the point is directly on the segment
if ( doubleNear( dist, 0.0, 0.00000001 ) )
if ( doubleNear( dist, 0.0, epsilon ) )
{
minDistPoint.setX( m_x );
minDistPoint.setY( m_y );
Expand Down
4 changes: 3 additions & 1 deletion src/core/qgspoint.h
Expand Up @@ -18,6 +18,8 @@
#ifndef QGSPOINT_H
#define QGSPOINT_H

#include <qgis.h>

#include <iostream>
#include <QString>
#include <QPoint>
Expand Down Expand Up @@ -146,7 +148,7 @@ class CORE_EXPORT QgsPoint

/**Returns the minimum distance between this point and a segment
@note added in QGIS 1.5*/
double sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint ) const;
double sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint, double epsilon = DEFAULT_SEGMENT_EPSILON ) const;

/**Calculates azimut between this point and other one (clockwise in degree, starting from north)
@note: this function has been added in version 1.7*/
Expand Down
3 changes: 1 addition & 2 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -4285,7 +4285,7 @@ void QgsVectorLayer::snapToGeometry( const QgsPoint& startPoint,
{
if ( geometryType() != QGis::Point ) // cannot snap to segment for points/multipoints
{
sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex );
sqrDistSegmentSnap = geom->closestSegmentWithContext( startPoint, snappedPoint, afterVertex, NULL, crs().geographicFlag() ? 1e-12 : 1e-8 );

if ( sqrDistSegmentSnap < sqrSnappingTolerance )
{
Expand All @@ -4301,7 +4301,6 @@ void QgsVectorLayer::snapToGeometry( const QgsPoint& startPoint,
}
}
}

}

int QgsVectorLayer::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults )
Expand Down
3 changes: 2 additions & 1 deletion src/gui/qgsprojectionselector.h
Expand Up @@ -184,7 +184,6 @@ class GUI_EXPORT QgsProjectionSelector: public QWidget, private Ui::QgsProjectio
//! Has the User Projection List been populated?
bool mUserProjListDone;

bool mSkipFirstRecent;

//! Has the Recent Projection List been populated?
bool mRecentProjListDone;
Expand All @@ -193,6 +192,8 @@ class GUI_EXPORT QgsProjectionSelector: public QWidget, private Ui::QgsProjectio
int mSearchColumn;
QString mSearchValue;

bool mSkipFirstRecent;

//! The set of OGC WMS CRSs that want to be applied to this widget
QSet<QString> mCrsFilter;

Expand Down

0 comments on commit b870b55

Please sign in to comment.