mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -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()
|
||||
|
||||
: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
|
||||
|
||||
};
|
||||
|
@ -149,6 +149,22 @@ canvasMoveEvent is triggered and it's not hidden by the cad's
|
||||
construction mode.
|
||||
|
||||
: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
|
||||
|
||||
};
|
||||
|
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/qgsshortcutsmanager.sip
|
||||
%Include auto_generated/qgsslider.sip
|
||||
%Include auto_generated/qgssnaptogridcanvasitem.sip
|
||||
%Include auto_generated/qgsstatusbar.sip
|
||||
%Include auto_generated/qgssublayersdialog.sip
|
||||
%Include auto_generated/qgssubstitutionlistwidget.sip
|
||||
|
@ -27,6 +27,7 @@ QgsMapToolSplitFeatures::QgsMapToolSplitFeatures( QgsMapCanvas *canvas )
|
||||
: QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), QgsMapToolCapture::CaptureLine )
|
||||
{
|
||||
mToolName = tr( "Split features" );
|
||||
setSnapToLayerGridEnabled( false );
|
||||
}
|
||||
|
||||
void QgsMapToolSplitFeatures::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
|
||||
|
@ -27,6 +27,7 @@ QgsMapToolSplitParts::QgsMapToolSplitParts( QgsMapCanvas *canvas )
|
||||
: QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), QgsMapToolCapture::CaptureLine )
|
||||
{
|
||||
mToolName = tr( "Split parts" );
|
||||
setSnapToLayerGridEnabled( false );
|
||||
}
|
||||
|
||||
void QgsMapToolSplitParts::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
|
||||
|
@ -47,7 +47,7 @@ bool QgsVectorLayerEditUtils::insertVertex( double x, double y, QgsFeatureId atF
|
||||
|
||||
geometry.insertVertex( x, y, beforeVertex );
|
||||
|
||||
mLayer->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
mLayer->changeGeometry( atFeatureId, geometry );
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ bool QgsVectorLayerEditUtils::insertVertex( const QgsPoint &point, QgsFeatureId
|
||||
|
||||
geometry.insertVertex( point, beforeVertex );
|
||||
|
||||
mLayer->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
mLayer->changeGeometry( atFeatureId, geometry );
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ bool QgsVectorLayerEditUtils::moveVertex( const QgsPoint &p, QgsFeatureId atFeat
|
||||
|
||||
geometry.moveVertex( p, atVertex );
|
||||
|
||||
mLayer->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
mLayer->changeGeometry( atFeatureId, geometry );
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ QgsVectorLayer::EditResult QgsVectorLayerEditUtils::deleteVertex( QgsFeatureId f
|
||||
geometry.set( nullptr );
|
||||
}
|
||||
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->changeGeometry( featureId, geometry );
|
||||
return !geometry.isNull() ? QgsVectorLayer::Success : QgsVectorLayer::EmptyGeometry;
|
||||
}
|
||||
|
||||
@ -159,7 +159,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::addRing( QgsCurve *ring, c
|
||||
if ( addRingReturnCode == 0 )
|
||||
if ( addRingReturnCode == QgsGeometry::Success )
|
||||
{
|
||||
mLayer->editBuffer()->changeGeometry( f.id(), g );
|
||||
mLayer->changeGeometry( f.id(), g );
|
||||
if ( modifiedFeatureId )
|
||||
*modifiedFeatureId = f.id();
|
||||
|
||||
@ -212,7 +212,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( const QgsPointSeq
|
||||
//convert back to single part if required by layer
|
||||
geometry.convertToSingleType();
|
||||
}
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->changeGeometry( featureId, geometry );
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
@ -247,7 +247,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( QgsCurve *ring, Q
|
||||
//convert back to single part if required by layer
|
||||
geometry.convertToSingleType();
|
||||
}
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->changeGeometry( featureId, geometry );
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
@ -267,7 +267,7 @@ int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx
|
||||
int errorCode = geometry.translate( dx, dy );
|
||||
if ( errorCode == 0 )
|
||||
{
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->changeGeometry( featureId, geometry );
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
@ -348,13 +348,13 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitFeatures( const QVect
|
||||
if ( splitFunctionReturn == QgsGeometry::OperationResult::Success )
|
||||
{
|
||||
//change this geometry
|
||||
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
mLayer->changeGeometry( feat.id(), featureGeom );
|
||||
|
||||
//insert new features
|
||||
for ( int i = 0; i < newGeometries.size(); ++i )
|
||||
{
|
||||
QgsFeature f = QgsVectorLayerUtils::createFeature( mLayer, newGeometries.at( i ), feat.attributes().toMap() );
|
||||
mLayer->editBuffer()->addFeature( f );
|
||||
mLayer->addFeature( f );
|
||||
}
|
||||
|
||||
if ( topologicalEditing )
|
||||
@ -470,7 +470,7 @@ QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitParts( const QVector<
|
||||
|
||||
if ( !addPartRet )
|
||||
{
|
||||
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
mLayer->changeGeometry( feat.id(), featureGeom );
|
||||
}
|
||||
|
||||
if ( topologicalEditing )
|
||||
|
@ -358,6 +358,7 @@ SET(QGIS_GUI_SRCS
|
||||
qgsshortcutsmanager.cpp
|
||||
qgsslider.cpp
|
||||
qgssnapindicator.cpp
|
||||
qgssnaptogridcanvasitem.cpp
|
||||
qgssublayersdialog.cpp
|
||||
qgssubstitutionlistwidget.cpp
|
||||
qgssqlcomposerdialog.cpp
|
||||
@ -527,6 +528,7 @@ SET(QGIS_GUI_MOC_HDRS
|
||||
qgssearchquerybuilder.h
|
||||
qgsshortcutsmanager.h
|
||||
qgsslider.h
|
||||
qgssnaptogridcanvasitem.h
|
||||
qgssqlcomposerdialog.h
|
||||
qgsstatusbar.h
|
||||
qgssublayersdialog.h
|
||||
|
@ -71,6 +71,30 @@ void QgsMapMouseEvent::setMapPoint( const QgsPointXY &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 )
|
||||
{
|
||||
double x = point.x(), y = point.y();
|
||||
|
@ -126,6 +126,15 @@ class GUI_EXPORT QgsMapMouseEvent : public QMouseEvent
|
||||
*/
|
||||
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:
|
||||
|
||||
QPoint mapToPixelCoordinates( const QgsPointXY &point );
|
||||
|
@ -17,11 +17,15 @@
|
||||
#include "qgsmaptooladvanceddigitizing.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsadvanceddigitizingdockwidget.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsgeometryfixes.h"
|
||||
#include "qgssnaptogridcanvasitem.h"
|
||||
|
||||
QgsMapToolAdvancedDigitizing::QgsMapToolAdvancedDigitizing( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
|
||||
: QgsMapToolEdit( canvas )
|
||||
, mCadDockWidget( cadDockWidget )
|
||||
{
|
||||
connect( canvas, &QgsMapCanvas::currentLayerChanged, this, &QgsMapToolAdvancedDigitizing::onCurrentLayerChanged );
|
||||
}
|
||||
|
||||
void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
|
||||
@ -38,6 +42,12 @@ void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
|
||||
e->snapPoint();
|
||||
}
|
||||
|
||||
QgsVectorLayer *layer = currentVectorLayer();
|
||||
if ( mSnapToLayerGridEnabled && layer )
|
||||
{
|
||||
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
|
||||
}
|
||||
|
||||
cadCanvasPressEvent( e );
|
||||
}
|
||||
|
||||
@ -72,6 +82,12 @@ void QgsMapToolAdvancedDigitizing::canvasReleaseEvent( QgsMapMouseEvent *e )
|
||||
e->snapPoint();
|
||||
}
|
||||
|
||||
QgsVectorLayer *layer = currentVectorLayer();
|
||||
if ( mSnapToLayerGridEnabled && layer )
|
||||
{
|
||||
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
|
||||
}
|
||||
|
||||
cadCanvasReleaseEvent( e );
|
||||
}
|
||||
|
||||
@ -91,6 +107,13 @@ void QgsMapToolAdvancedDigitizing::canvasMoveEvent( QgsMapMouseEvent *e )
|
||||
e->snapPoint();
|
||||
}
|
||||
|
||||
QgsVectorLayer *layer = currentVectorLayer();
|
||||
if ( mSnapToLayerGridEnabled && layer )
|
||||
{
|
||||
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
|
||||
mSnapToGridCanvasItem->setPoint( e->mapPoint() );
|
||||
}
|
||||
|
||||
cadCanvasMoveEvent( e );
|
||||
}
|
||||
|
||||
@ -99,6 +122,14 @@ void QgsMapToolAdvancedDigitizing::activate()
|
||||
QgsMapToolEdit::activate();
|
||||
connect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChanged, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
|
||||
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()
|
||||
@ -106,6 +137,8 @@ void QgsMapToolAdvancedDigitizing::deactivate()
|
||||
QgsMapToolEdit::deactivate();
|
||||
disconnect( mCadDockWidget, &QgsAdvancedDigitizingDockWidget::pointChanged, this, &QgsMapToolAdvancedDigitizing::cadPointChanged );
|
||||
mCadDockWidget->disable();
|
||||
delete mSnapToGridCanvasItem;
|
||||
mSnapToGridCanvasItem = nullptr;
|
||||
}
|
||||
|
||||
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 );
|
||||
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 QgsAdvancedDigitizingDockWidget;
|
||||
class QgsSnapToGridCanvasItem;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
@ -140,6 +141,22 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
|
||||
*/
|
||||
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:
|
||||
|
||||
/**
|
||||
@ -152,6 +169,8 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
|
||||
*/
|
||||
void cadPointChanged( const QgsPointXY &point );
|
||||
|
||||
void onCurrentLayerChanged();
|
||||
|
||||
private:
|
||||
QgsAdvancedDigitizingDockWidget *mCadDockWidget = nullptr;
|
||||
|
||||
@ -159,6 +178,9 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
|
||||
bool mAdvancedDigitizingAllowed = true;
|
||||
//! Whether to snap mouse cursor to map before passing coordinates to cadCanvas*Event()
|
||||
bool mAutoSnapEnabled = true;
|
||||
//! Whether to snap to grid before passing coordinates to cadCanvas*Event()
|
||||
bool mSnapToLayerGridEnabled = true;
|
||||
QgsSnapToGridCanvasItem *mSnapToGridCanvasItem = nullptr;
|
||||
};
|
||||
|
||||
#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