mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Merge pull request #7711 from m-kuhn/mapToolSnapToGrid
Snap to grid for maptools [FEATURE]
This commit is contained in:
commit
32ee71634f
@ -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
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
|
||||||
};
|
};
|
||||||
|
92
python/gui/auto_generated/qgssnaptogridcanvasitem.sip.in
Normal file
92
python/gui/auto_generated/qgssnaptogridcanvasitem.sip.in
Normal file
@ -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 *
|
||||||
|
************************************************************************/
|
@ -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
|
||||||
|
@ -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 )
|
||||||
|
@ -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 )
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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();
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -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 )
|
||||||
@ -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 )
|
||||||
|
@ -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
|
||||||
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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 );
|
||||||
|
@ -17,11 +17,15 @@
|
|||||||
#include "qgsmaptooladvanceddigitizing.h"
|
#include "qgsmaptooladvanceddigitizing.h"
|
||||||
#include "qgsmapcanvas.h"
|
#include "qgsmapcanvas.h"
|
||||||
#include "qgsadvanceddigitizingdockwidget.h"
|
#include "qgsadvanceddigitizingdockwidget.h"
|
||||||
|
#include "qgsvectorlayer.h"
|
||||||
|
#include "qgsgeometryfixes.h"
|
||||||
|
#include "qgssnaptogridcanvasitem.h"
|
||||||
|
|
||||||
QgsMapToolAdvancedDigitizing::QgsMapToolAdvancedDigitizing( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
|
QgsMapToolAdvancedDigitizing::QgsMapToolAdvancedDigitizing( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
|
||||||
: QgsMapToolEdit( canvas )
|
: QgsMapToolEdit( canvas )
|
||||||
, mCadDockWidget( cadDockWidget )
|
, mCadDockWidget( cadDockWidget )
|
||||||
{
|
{
|
||||||
|
connect( canvas, &QgsMapCanvas::currentLayerChanged, this, &QgsMapToolAdvancedDigitizing::onCurrentLayerChanged );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
|
void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
|
||||||
@ -38,6 +42,12 @@ void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
|
|||||||
e->snapPoint();
|
e->snapPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsVectorLayer *layer = currentVectorLayer();
|
||||||
|
if ( mSnapToLayerGridEnabled && layer )
|
||||||
|
{
|
||||||
|
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
|
||||||
|
}
|
||||||
|
|
||||||
cadCanvasPressEvent( e );
|
cadCanvasPressEvent( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +82,12 @@ void QgsMapToolAdvancedDigitizing::canvasReleaseEvent( QgsMapMouseEvent *e )
|
|||||||
e->snapPoint();
|
e->snapPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsVectorLayer *layer = currentVectorLayer();
|
||||||
|
if ( mSnapToLayerGridEnabled && layer )
|
||||||
|
{
|
||||||
|
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
|
||||||
|
}
|
||||||
|
|
||||||
cadCanvasReleaseEvent( e );
|
cadCanvasReleaseEvent( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +107,13 @@ void QgsMapToolAdvancedDigitizing::canvasMoveEvent( QgsMapMouseEvent *e )
|
|||||||
e->snapPoint();
|
e->snapPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsVectorLayer *layer = currentVectorLayer();
|
||||||
|
if ( mSnapToLayerGridEnabled && layer )
|
||||||
|
{
|
||||||
|
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
|
||||||
|
mSnapToGridCanvasItem->setPoint( e->mapPoint() );
|
||||||
|
}
|
||||||
|
|
||||||
cadCanvasMoveEvent( e );
|
cadCanvasMoveEvent( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +122,14 @@ void QgsMapToolAdvancedDigitizing::activate()
|
|||||||
QgsMapToolEdit::activate();
|
QgsMapToolEdit::activate();
|
||||||
connect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChanged, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
|
connect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChanged, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
|
||||||
mCadDockWidget->enable();
|
mCadDockWidget->enable();
|
||||||
|
mSnapToGridCanvasItem = new QgsSnapToGridCanvasItem( mCanvas );
|
||||||
|
QgsVectorLayer *layer = currentVectorLayer();
|
||||||
|
if ( layer )
|
||||||
|
{
|
||||||
|
mSnapToGridCanvasItem->setCrs( currentVectorLayer()->crs() );
|
||||||
|
mSnapToGridCanvasItem->setPrecision( currentVectorLayer()->geometryFixes()->geometryPrecision() );
|
||||||
|
}
|
||||||
|
mSnapToGridCanvasItem->setEnabled( mSnapToLayerGridEnabled );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMapToolAdvancedDigitizing::deactivate()
|
void QgsMapToolAdvancedDigitizing::deactivate()
|
||||||
@ -106,6 +137,8 @@ void QgsMapToolAdvancedDigitizing::deactivate()
|
|||||||
QgsMapToolEdit::deactivate();
|
QgsMapToolEdit::deactivate();
|
||||||
disconnect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChanged, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
|
disconnect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChanged, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
|
||||||
mCadDockWidget->disable();
|
mCadDockWidget->disable();
|
||||||
|
delete mSnapToGridCanvasItem;
|
||||||
|
mSnapToGridCanvasItem = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMapToolAdvancedDigitizing::cadPointChanged( const QgsPointXY &point )
|
void QgsMapToolAdvancedDigitizing::cadPointChanged( const QgsPointXY &point )
|
||||||
@ -114,3 +147,36 @@ void QgsMapToolAdvancedDigitizing::cadPointChanged( const QgsPointXY &point )
|
|||||||
QMouseEvent *ev = new QMouseEvent( QEvent::MouseMove, mCanvas->mouseLastXY(), Qt::NoButton, Qt::NoButton, Qt::NoModifier );
|
QMouseEvent *ev = new QMouseEvent( QEvent::MouseMove, mCanvas->mouseLastXY(), Qt::NoButton, Qt::NoButton, Qt::NoModifier );
|
||||||
qApp->postEvent( mCanvas->viewport(), ev ); // event queue will delete the event when processed
|
qApp->postEvent( mCanvas->viewport(), ev ); // event queue will delete the event when processed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsMapToolAdvancedDigitizing::onCurrentLayerChanged()
|
||||||
|
{
|
||||||
|
if ( mSnapToGridCanvasItem )
|
||||||
|
{
|
||||||
|
QgsVectorLayer *layer = currentVectorLayer();
|
||||||
|
if ( layer && mSnapToLayerGridEnabled )
|
||||||
|
{
|
||||||
|
mSnapToGridCanvasItem->setPrecision( layer->geometryFixes()->geometryPrecision() );
|
||||||
|
mSnapToGridCanvasItem->setCrs( layer->crs() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !layer )
|
||||||
|
mSnapToGridCanvasItem->setEnabled( false );
|
||||||
|
else
|
||||||
|
mSnapToGridCanvasItem->setEnabled( mSnapToLayerGridEnabled );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsMapToolAdvancedDigitizing::snapToLayerGridEnabled() const
|
||||||
|
{
|
||||||
|
return mSnapToLayerGridEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsMapToolAdvancedDigitizing::setSnapToLayerGridEnabled( bool snapToGridEnabled )
|
||||||
|
{
|
||||||
|
mSnapToLayerGridEnabled = snapToGridEnabled;
|
||||||
|
|
||||||
|
if ( mSnapToGridCanvasItem )
|
||||||
|
{
|
||||||
|
mSnapToGridCanvasItem->setEnabled( snapToGridEnabled );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
class QgsMapMouseEvent;
|
class QgsMapMouseEvent;
|
||||||
class QgsAdvancedDigitizingDockWidget;
|
class QgsAdvancedDigitizingDockWidget;
|
||||||
|
class QgsSnapToGridCanvasItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup gui
|
* \ingroup gui
|
||||||
@ -140,6 +141,22 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
|
|||||||
*/
|
*/
|
||||||
virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e ) { Q_UNUSED( e ) }
|
virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e ) { Q_UNUSED( e ) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables snap to grid of mouse events.
|
||||||
|
* The snapping will occur in the layer's CRS.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.4
|
||||||
|
*/
|
||||||
|
bool snapToLayerGridEnabled() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables snap to grid of mouse events.
|
||||||
|
* The snapping will occur in the layer's CRS.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.4
|
||||||
|
*/
|
||||||
|
void setSnapToLayerGridEnabled( bool snapToLayerGridEnabled );
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,6 +169,8 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
|
|||||||
*/
|
*/
|
||||||
void cadPointChanged( const QgsPointXY &point );
|
void cadPointChanged( const QgsPointXY &point );
|
||||||
|
|
||||||
|
void onCurrentLayerChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QgsAdvancedDigitizingDockWidget *mCadDockWidget = nullptr;
|
QgsAdvancedDigitizingDockWidget *mCadDockWidget = nullptr;
|
||||||
|
|
||||||
@ -159,6 +178,9 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
|
|||||||
bool mAdvancedDigitizingAllowed = true;
|
bool mAdvancedDigitizingAllowed = true;
|
||||||
//! Whether to snap mouse cursor to map before passing coordinates to cadCanvas*Event()
|
//! Whether to snap mouse cursor to map before passing coordinates to cadCanvas*Event()
|
||||||
bool mAutoSnapEnabled = true;
|
bool mAutoSnapEnabled = true;
|
||||||
|
//! Whether to snap to grid before passing coordinates to cadCanvas*Event()
|
||||||
|
bool mSnapToLayerGridEnabled = true;
|
||||||
|
QgsSnapToGridCanvasItem *mSnapToGridCanvasItem = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QGSMAPTOOLADVANCEDDIGITIZE_H
|
#endif // QGSMAPTOOLADVANCEDDIGITIZE_H
|
||||||
|
170
src/gui/qgssnaptogridcanvasitem.cpp
Normal file
170
src/gui/qgssnaptogridcanvasitem.cpp
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgssnaptogridcanvasitem.cpp
|
||||||
|
----------------------
|
||||||
|
begin : August 2018
|
||||||
|
copyright : (C) Matthias Kuhn
|
||||||
|
email : matthias@opengis.ch
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "qgssnaptogridcanvasitem.h"
|
||||||
|
#include "qgsmapcanvas.h"
|
||||||
|
|
||||||
|
QgsSnapToGridCanvasItem::QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas )
|
||||||
|
: QgsMapCanvasItem( mapCanvas )
|
||||||
|
{
|
||||||
|
updateMapCanvasCrs();
|
||||||
|
connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsSnapToGridCanvasItem::updateZoomFactor );
|
||||||
|
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsSnapToGridCanvasItem::updateMapCanvasCrs );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::paint( QPainter *painter )
|
||||||
|
{
|
||||||
|
if ( !mEnabled || !mAvailableByZoomFactor )
|
||||||
|
return;
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
QgsRectangle mapRect = mMapCanvas->extent();
|
||||||
|
if ( rect() != mapRect )
|
||||||
|
setRect( mapRect );
|
||||||
|
|
||||||
|
painter->setRenderHints( QPainter::Antialiasing );
|
||||||
|
painter->setCompositionMode( QPainter::CompositionMode_Difference );
|
||||||
|
|
||||||
|
double scaleFactor = painter->fontMetrics().xHeight() * .2;
|
||||||
|
|
||||||
|
mGridPen.setWidth( scaleFactor );
|
||||||
|
mCurrentPointPen.setWidth( scaleFactor * 3 );
|
||||||
|
const int gridMarkerLength = scaleFactor * 3;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const QgsRectangle layerExtent = mTransform.transformBoundingBox( mapRect, QgsCoordinateTransform::ReverseTransform );
|
||||||
|
const QgsPointXY layerPt = mTransform.transform( mPoint, QgsCoordinateTransform::ReverseTransform );
|
||||||
|
|
||||||
|
const double gridXMin = std::ceil( layerExtent.xMinimum() / mPrecision ) * mPrecision;
|
||||||
|
const double gridXMax = std::ceil( layerExtent.xMaximum() / mPrecision ) * mPrecision;
|
||||||
|
const double gridYMin = std::ceil( layerExtent.yMinimum() / mPrecision ) * mPrecision;
|
||||||
|
const double gridYMax = std::ceil( layerExtent.yMaximum() / mPrecision ) * mPrecision;
|
||||||
|
|
||||||
|
for ( int x = gridXMin ; x < gridXMax; x += mPrecision )
|
||||||
|
{
|
||||||
|
for ( int y = gridYMin ; y < gridYMax; y += mPrecision )
|
||||||
|
{
|
||||||
|
const QgsPointXY pt = mTransform.transform( x, y );
|
||||||
|
const QPointF canvasPt = toCanvasCoordinates( pt );
|
||||||
|
|
||||||
|
if ( qgsDoubleNear( layerPt.x(), x, mPrecision / 2 ) && qgsDoubleNear( layerPt.y(), y, mPrecision / 2 ) )
|
||||||
|
{
|
||||||
|
painter->setPen( mCurrentPointPen );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter->setPen( mGridPen );
|
||||||
|
}
|
||||||
|
painter->drawLine( canvasPt.x() - gridMarkerLength, canvasPt.y(), canvasPt.x() + gridMarkerLength, canvasPt.y() );
|
||||||
|
painter->drawLine( canvasPt.x(), canvasPt.y() - gridMarkerLength, canvasPt.x(), canvasPt.y() + gridMarkerLength );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( QgsCsException &e )
|
||||||
|
{
|
||||||
|
Q_UNUSED( e )
|
||||||
|
mAvailableByZoomFactor = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsPointXY QgsSnapToGridCanvasItem::point() const
|
||||||
|
{
|
||||||
|
return mPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::setPoint( const QgsPointXY &point )
|
||||||
|
{
|
||||||
|
mPoint = point;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
double QgsSnapToGridCanvasItem::precision() const
|
||||||
|
{
|
||||||
|
return mPrecision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::setPrecision( double precision )
|
||||||
|
{
|
||||||
|
mPrecision = precision;
|
||||||
|
updateZoomFactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsCoordinateReferenceSystem QgsSnapToGridCanvasItem::crs() const
|
||||||
|
{
|
||||||
|
return mTransform.sourceCrs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::setCrs( const QgsCoordinateReferenceSystem &crs )
|
||||||
|
{
|
||||||
|
mTransform.setSourceCrs( crs );
|
||||||
|
updateZoomFactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsSnapToGridCanvasItem::enabled() const
|
||||||
|
{
|
||||||
|
return mEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::setEnabled( bool enabled )
|
||||||
|
{
|
||||||
|
mEnabled = enabled;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::updateMapCanvasCrs()
|
||||||
|
{
|
||||||
|
mTransform.setContext( mMapCanvas->mapSettings().transformContext() );
|
||||||
|
mTransform.setDestinationCrs( mMapCanvas->mapSettings().destinationCrs() );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void QgsSnapToGridCanvasItem::updateZoomFactor()
|
||||||
|
{
|
||||||
|
if ( !isVisible() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const int threshold = 5;
|
||||||
|
|
||||||
|
const QgsPointXY centerPoint = mMapCanvas->extent().center();
|
||||||
|
const QPointF canvasCenter = toCanvasCoordinates( centerPoint );
|
||||||
|
|
||||||
|
const QgsPointXY pt1 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( canvasCenter.x() - threshold, canvasCenter.y() - threshold );
|
||||||
|
const QgsPointXY pt2 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( canvasCenter.x() + threshold, canvasCenter.y() + threshold );
|
||||||
|
|
||||||
|
const QgsPointXY layerPt1 = mTransform.transform( pt1, QgsCoordinateTransform::ReverseTransform );
|
||||||
|
const QgsPointXY layerPt2 = mTransform.transform( pt2, QgsCoordinateTransform::ReverseTransform );
|
||||||
|
|
||||||
|
const double dist = layerPt1.distance( layerPt2 );
|
||||||
|
|
||||||
|
if ( dist < mPrecision )
|
||||||
|
mAvailableByZoomFactor = true;
|
||||||
|
else
|
||||||
|
mAvailableByZoomFactor = false;
|
||||||
|
}
|
||||||
|
catch ( QgsCsException &e )
|
||||||
|
{
|
||||||
|
// transform errors?
|
||||||
|
// you've probably got worse problems than the grid with your digitizing operations in the current projection.
|
||||||
|
mAvailableByZoomFactor = false;
|
||||||
|
}
|
||||||
|
}
|
113
src/gui/qgssnaptogridcanvasitem.h
Normal file
113
src/gui/qgssnaptogridcanvasitem.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgssnaptogridcanvasitem.h
|
||||||
|
----------------------
|
||||||
|
begin : August 2018
|
||||||
|
copyright : (C) Matthias Kuhn
|
||||||
|
email : matthias@opengis.ch
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QGSSNAPTOGRIDCANVASITEM_H
|
||||||
|
#define QGSSNAPTOGRIDCANVASITEM_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPen>
|
||||||
|
|
||||||
|
#include "qgscoordinatereferencesystem.h"
|
||||||
|
#include "qgsmapcanvasitem.h"
|
||||||
|
#include "qgscoordinatetransform.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \ingroup gui
|
||||||
|
*
|
||||||
|
* Shows a grid on the map canvas given a spatial resolution.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.4
|
||||||
|
*/
|
||||||
|
class GUI_EXPORT QgsSnapToGridCanvasItem : public QObject, public QgsMapCanvasItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will automatically be added to the \a mapCanvas.
|
||||||
|
*/
|
||||||
|
QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas SIP_TRANSFERTHIS );
|
||||||
|
|
||||||
|
void paint( QPainter *painter ) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
QgsPointXY point() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void setPoint( const QgsPointXY &point );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resolution of the grid in map units.
|
||||||
|
* If a crs has been specified it will be in CRS units.
|
||||||
|
*/
|
||||||
|
double precision() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resolution of the grid in map units.
|
||||||
|
* If a crs has been specified it will be in CRS units.
|
||||||
|
*/
|
||||||
|
void setPrecision( double precision );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
QgsCoordinateReferenceSystem crs() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void setCrs( const QgsCoordinateReferenceSystem &crs );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable this item. It will be hidden if disabled.
|
||||||
|
*/
|
||||||
|
bool enabled() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable this item. It will be hidden if disabled.
|
||||||
|
*/
|
||||||
|
void setEnabled( bool enabled );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateMapCanvasCrs();
|
||||||
|
|
||||||
|
void updateZoomFactor();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPen mGridPen = QPen( QColor( 127, 127, 127, 150 ) );
|
||||||
|
QPen mCurrentPointPen = QPen( QColor( 200, 200, 200, 150 ) );
|
||||||
|
|
||||||
|
bool mEnabled = true;
|
||||||
|
bool mAvailableByZoomFactor = false;
|
||||||
|
|
||||||
|
double mPrecision = 0.0;
|
||||||
|
QgsCoordinateTransform mTransform;
|
||||||
|
QgsPointXY mPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QGSSNAPTOGRIDCANVASITEM_H
|
Loading…
x
Reference in New Issue
Block a user