Skip to content

Commit

Permalink
Merge pull request #7711 from m-kuhn/mapToolSnapToGrid
Browse files Browse the repository at this point in the history
Snap to grid for maptools [FEATURE]
  • Loading branch information
m-kuhn committed Sep 8, 2018
2 parents 0cc9501 + d57c184 commit 32ee716
Show file tree
Hide file tree
Showing 14 changed files with 537 additions and 11 deletions.
9 changes: 9 additions & 0 deletions python/gui/auto_generated/qgsmapmouseevent.sip.in
Expand Up @@ -117,6 +117,15 @@ The unsnapped, real mouse cursor position in pixel coordinates.
Alias to pos() Alias to pos()


:return: Mouse position in pixel coordinates :return: Mouse position in pixel coordinates
%End

void snapToGrid( double precision, const QgsCoordinateReferenceSystem &crs );
%Docstring
Snaps the mapPoint to a grid with the given ``precision``.
The snapping will be done in the specified ``crs``. If this crs is
different from the mapCanvas crs, it will be reprojected on the fly.

.. versionadded:: 3.4
%End %End


}; };
Expand Down
16 changes: 16 additions & 0 deletions python/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
Expand Up @@ -149,6 +149,22 @@ canvasMoveEvent is triggered and it's not hidden by the cad's
construction mode. construction mode.


:param e: Mouse events prepared by the cad system :param e: Mouse events prepared by the cad system
%End

bool snapToLayerGridEnabled() const;
%Docstring
Enables or disables snap to grid of mouse events.
The snapping will occur in the layer's CRS.

.. versionadded:: 3.4
%End

void setSnapToLayerGridEnabled( bool snapToLayerGridEnabled );
%Docstring
Enables or disables snap to grid of mouse events.
The snapping will occur in the layer's CRS.

.. versionadded:: 3.4
%End %End


}; };
Expand Down
92 changes: 92 additions & 0 deletions python/gui/auto_generated/qgssnaptogridcanvasitem.sip.in
@@ -0,0 +1,92 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgssnaptogridcanvasitem.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsSnapToGridCanvasItem : QObject, QgsMapCanvasItem
{
%Docstring

Shows a grid on the map canvas given a spatial resolution.

.. versionadded:: 3.4
%End

%TypeHeaderCode
#include "qgssnaptogridcanvasitem.h"
%End
public:

QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas /TransferThis/ );
%Docstring
Will automatically be added to the ``mapCanvas``.
%End

virtual void paint( QPainter *painter );


QgsPointXY point() const;
%Docstring
A point that will be highlighted on the map canvas.
The point needs to be in map coordinates. The closest point on the
grid will be highlighted.
%End

void setPoint( const QgsPointXY &point );
%Docstring
A point that will be highlighted on the map canvas.
The point needs to be in map coordinates. The closest point on the
grid will be highlighted.
%End

double precision() const;
%Docstring
The resolution of the grid in map units.
If a crs has been specified it will be in CRS units.
%End

void setPrecision( double precision );
%Docstring
The resolution of the grid in map units.
If a crs has been specified it will be in CRS units.
%End

QgsCoordinateReferenceSystem crs() const;
%Docstring
The CRS in which the grid should be calculated.
By default will be an invalid QgsCoordinateReferenceSystem and
as such equal to the CRS of the map canvas.
%End

void setCrs( const QgsCoordinateReferenceSystem &crs );
%Docstring
The CRS in which the grid should be calculated.
By default will be an invalid QgsCoordinateReferenceSystem and
as such equal to the CRS of the map canvas.
%End

bool enabled() const;
%Docstring
Enable this item. It will be hidden if disabled.
%End

void setEnabled( bool enabled );
%Docstring
Enable this item. It will be hidden if disabled.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgssnaptogridcanvasitem.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/gui/gui_auto.sip
Expand Up @@ -193,6 +193,7 @@
%Include auto_generated/qgssearchquerybuilder.sip %Include auto_generated/qgssearchquerybuilder.sip
%Include auto_generated/qgsshortcutsmanager.sip %Include auto_generated/qgsshortcutsmanager.sip
%Include auto_generated/qgsslider.sip %Include auto_generated/qgsslider.sip
%Include auto_generated/qgssnaptogridcanvasitem.sip
%Include auto_generated/qgsstatusbar.sip %Include auto_generated/qgsstatusbar.sip
%Include auto_generated/qgssublayersdialog.sip %Include auto_generated/qgssublayersdialog.sip
%Include auto_generated/qgssubstitutionlistwidget.sip %Include auto_generated/qgssubstitutionlistwidget.sip
Expand Down
1 change: 1 addition & 0 deletions src/app/qgsmaptoolsplitfeatures.cpp
Expand Up @@ -27,6 +27,7 @@ QgsMapToolSplitFeatures::QgsMapToolSplitFeatures( QgsMapCanvas *canvas )
: QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), QgsMapToolCapture::CaptureLine ) : QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), QgsMapToolCapture::CaptureLine )
{ {
mToolName = tr( "Split features" ); mToolName = tr( "Split features" );
setSnapToLayerGridEnabled( false );
} }


void QgsMapToolSplitFeatures::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) void QgsMapToolSplitFeatures::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
Expand Down
1 change: 1 addition & 0 deletions src/app/qgsmaptoolsplitparts.cpp
Expand Up @@ -27,6 +27,7 @@ QgsMapToolSplitParts::QgsMapToolSplitParts( QgsMapCanvas *canvas )
: QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), QgsMapToolCapture::CaptureLine ) : QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), QgsMapToolCapture::CaptureLine )
{ {
mToolName = tr( "Split parts" ); mToolName = tr( "Split parts" );
setSnapToLayerGridEnabled( false );
} }


void QgsMapToolSplitParts::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) void QgsMapToolSplitParts::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
Expand Down
22 changes: 11 additions & 11 deletions src/core/qgsvectorlayereditutils.cpp
Expand Up @@ -47,7 +47,7 @@ bool QgsVectorLayerEditUtils::insertVertex( double x, double y, QgsFeatureId atF


geometry.insertVertex( x, y, beforeVertex ); geometry.insertVertex( x, y, beforeVertex );


mLayer->editBuffer()->changeGeometry( atFeatureId, geometry ); mLayer->changeGeometry( atFeatureId, geometry );
return true; return true;
} }


Expand All @@ -64,7 +64,7 @@ bool QgsVectorLayerEditUtils::insertVertex( const QgsPoint &point, QgsFeatureId


geometry.insertVertex( point, beforeVertex ); geometry.insertVertex( point, beforeVertex );


mLayer->editBuffer()->changeGeometry( atFeatureId, geometry ); mLayer->changeGeometry( atFeatureId, geometry );
return true; return true;
} }


Expand All @@ -87,7 +87,7 @@ bool QgsVectorLayerEditUtils::moveVertex( const QgsPoint &p, QgsFeatureId atFeat


geometry.moveVertex( p, atVertex ); geometry.moveVertex( p, atVertex );


mLayer->editBuffer()->changeGeometry( atFeatureId, geometry ); mLayer->changeGeometry( atFeatureId, geometry );
return true; return true;
} }


Expand All @@ -112,7 +112,7 @@ QgsVectorLayer::EditResult QgsVectorLayerEditUtils::deleteVertex( QgsFeatureId f
geometry.set( nullptr ); geometry.set( nullptr );
} }


mLayer->editBuffer()->changeGeometry( featureId, geometry ); mLayer->changeGeometry( featureId, geometry );
return !geometry.isNull() ? QgsVectorLayer::Success : QgsVectorLayer::EmptyGeometry; return !geometry.isNull() ? QgsVectorLayer::Success : QgsVectorLayer::EmptyGeometry;
} }


Expand Down Expand Up @@ -159,7 +159,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::addRing( QgsCurve *ring, c
if ( addRingReturnCode == 0 ) if ( addRingReturnCode == 0 )
if ( addRingReturnCode == QgsGeometry::Success ) if ( addRingReturnCode == QgsGeometry::Success )
{ {
mLayer->editBuffer()->changeGeometry( f.id(), g ); mLayer->changeGeometry( f.id(), g );
if ( modifiedFeatureId ) if ( modifiedFeatureId )
*modifiedFeatureId = f.id(); *modifiedFeatureId = f.id();


Expand Down Expand Up @@ -212,7 +212,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( const QgsPointSeq
//convert back to single part if required by layer //convert back to single part if required by layer
geometry.convertToSingleType(); geometry.convertToSingleType();
} }
mLayer->editBuffer()->changeGeometry( featureId, geometry ); mLayer->changeGeometry( featureId, geometry );
} }
return errorCode; return errorCode;
} }
Expand Down Expand Up @@ -247,7 +247,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( QgsCurve *ring, Q
//convert back to single part if required by layer //convert back to single part if required by layer
geometry.convertToSingleType(); geometry.convertToSingleType();
} }
mLayer->editBuffer()->changeGeometry( featureId, geometry ); mLayer->changeGeometry( featureId, geometry );
} }
return errorCode; return errorCode;
} }
Expand All @@ -267,7 +267,7 @@ int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx
int errorCode = geometry.translate( dx, dy ); int errorCode = geometry.translate( dx, dy );
if ( errorCode == 0 ) if ( errorCode == 0 )
{ {
mLayer->editBuffer()->changeGeometry( featureId, geometry ); mLayer->changeGeometry( featureId, geometry );
} }
return errorCode; return errorCode;
} }
Expand Down Expand Up @@ -348,13 +348,13 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitFeatures( const QVect
if ( splitFunctionReturn == QgsGeometry::OperationResult::Success ) if ( splitFunctionReturn == QgsGeometry::OperationResult::Success )
{ {
//change this geometry //change this geometry
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom ); mLayer->changeGeometry( feat.id(), featureGeom );


//insert new features //insert new features
for ( int i = 0; i < newGeometries.size(); ++i ) for ( int i = 0; i < newGeometries.size(); ++i )
{ {
QgsFeature f = QgsVectorLayerUtils::createFeature( mLayer, newGeometries.at( i ), feat.attributes().toMap() ); QgsFeature f = QgsVectorLayerUtils::createFeature( mLayer, newGeometries.at( i ), feat.attributes().toMap() );
mLayer->editBuffer()->addFeature( f ); mLayer->addFeature( f );
} }


if ( topologicalEditing ) if ( topologicalEditing )
Expand Down Expand Up @@ -470,7 +470,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitParts( const QVector<


if ( !addPartRet ) if ( !addPartRet )
{ {
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom ); mLayer->changeGeometry( feat.id(), featureGeom );
} }


if ( topologicalEditing ) if ( topologicalEditing )
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -358,6 +358,7 @@ SET(QGIS_GUI_SRCS
qgsshortcutsmanager.cpp qgsshortcutsmanager.cpp
qgsslider.cpp qgsslider.cpp
qgssnapindicator.cpp qgssnapindicator.cpp
qgssnaptogridcanvasitem.cpp
qgssublayersdialog.cpp qgssublayersdialog.cpp
qgssubstitutionlistwidget.cpp qgssubstitutionlistwidget.cpp
qgssqlcomposerdialog.cpp qgssqlcomposerdialog.cpp
Expand Down Expand Up @@ -527,6 +528,7 @@ SET(QGIS_GUI_MOC_HDRS
qgssearchquerybuilder.h qgssearchquerybuilder.h
qgsshortcutsmanager.h qgsshortcutsmanager.h
qgsslider.h qgsslider.h
qgssnaptogridcanvasitem.h
qgssqlcomposerdialog.h qgssqlcomposerdialog.h
qgsstatusbar.h qgsstatusbar.h
qgssublayersdialog.h qgssublayersdialog.h
Expand Down
24 changes: 24 additions & 0 deletions src/gui/qgsmapmouseevent.cpp
Expand Up @@ -71,6 +71,30 @@ void QgsMapMouseEvent::setMapPoint( const QgsPointXY &point )
mPixelPoint = mapToPixelCoordinates( point ); mPixelPoint = mapToPixelCoordinates( point );
} }


void QgsMapMouseEvent::snapToGrid( double precision, const QgsCoordinateReferenceSystem &crs )
{
if ( precision <= 0 )
return;

try
{
QgsCoordinateTransform ct( mMapCanvas->mapSettings().destinationCrs(), crs, mMapCanvas->mapSettings().transformContext() );

QgsPointXY pt = ct.transform( mMapPoint );

pt.setX( std::round( pt.x() / precision ) * precision );
pt.setY( std::round( pt.y() / precision ) * precision );

pt = ct.transform( pt, QgsCoordinateTransform::ReverseTransform );

setMapPoint( pt );
}
catch ( QgsCsException &e )
{
Q_UNUSED( e )
}
}

QPoint QgsMapMouseEvent::mapToPixelCoordinates( const QgsPointXY &point ) QPoint QgsMapMouseEvent::mapToPixelCoordinates( const QgsPointXY &point )
{ {
double x = point.x(), y = point.y(); double x = point.x(), y = point.y();
Expand Down
9 changes: 9 additions & 0 deletions src/gui/qgsmapmouseevent.h
Expand Up @@ -126,6 +126,15 @@ class GUI_EXPORT QgsMapMouseEvent : public QMouseEvent
*/ */
QPoint originalPixelPoint() const { return pos(); } QPoint originalPixelPoint() const { return pos(); }


/**
* Snaps the mapPoint to a grid with the given \a precision.
* The snapping will be done in the specified \a crs. If this crs is
* different from the mapCanvas crs, it will be reprojected on the fly.
*
* \since QGIS 3.4
*/
void snapToGrid( double precision, const QgsCoordinateReferenceSystem &crs );

private: private:


QPoint mapToPixelCoordinates( const QgsPointXY &point ); QPoint mapToPixelCoordinates( const QgsPointXY &point );
Expand Down

2 comments on commit 32ee716

@lajunek
Copy link

@lajunek lajunek commented on 32ee716 Mar 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-kuhn can you please describe the new feature for documentation 3.4 with more detail?

@m-kuhn
Copy link
Member Author

@m-kuhn m-kuhn commented on 32ee716 Mar 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lajunek
on the top of this page you find a link to #7711

image

Is that enough for you or do you need more?

Please sign in to comment.