Skip to content

Commit 1e81e03

Browse files
committed
Add QgsSnapToGridCanvasItem
1 parent fff743b commit 1e81e03

File tree

5 files changed

+334
-0
lines changed

5 files changed

+334
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/gui/qgssnaptogridcanvasitem.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
class QgsSnapToGridCanvasItem : QObject, QgsMapCanvasItem
12+
{
13+
%Docstring
14+
15+
Shows a grid on the map canvas given a spatial resolution.
16+
17+
.. versionadded:: 3.4
18+
%End
19+
20+
%TypeHeaderCode
21+
#include "qgssnaptogridcanvasitem.h"
22+
%End
23+
public:
24+
25+
QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas );
26+
%Docstring
27+
Will automatically be added to the ``mapCanvas``.
28+
%End
29+
30+
virtual void paint( QPainter *painter );
31+
32+
33+
QgsPointXY point() const;
34+
%Docstring
35+
A point that will be highlighted on the map canvas.
36+
The point needs to be in map coordinates. The closest point on the
37+
grid will be highlighted.
38+
%End
39+
40+
void setPoint( const QgsPointXY &point );
41+
%Docstring
42+
A point that will be highlighted on the map canvas.
43+
The point needs to be in map coordinates. The closest point on the
44+
grid will be highlighted.
45+
%End
46+
47+
double precision() const;
48+
%Docstring
49+
The resolution of the grid in map units.
50+
If a crs has been specified it will be in CRS units.
51+
%End
52+
53+
void setPrecision( double precision );
54+
%Docstring
55+
The resolution of the grid in map units.
56+
If a crs has been specified it will be in CRS units.
57+
%End
58+
59+
QgsCoordinateReferenceSystem crs() const;
60+
%Docstring
61+
The CRS in which the grid should be calculated.
62+
By default will be an invalid QgsCoordinateReferenceSystem and
63+
as such equal to the CRS of the map canvas.
64+
%End
65+
66+
void setCrs( const QgsCoordinateReferenceSystem &crs );
67+
%Docstring
68+
The CRS in which the grid should be calculated.
69+
By default will be an invalid QgsCoordinateReferenceSystem and
70+
as such equal to the CRS of the map canvas.
71+
%End
72+
73+
bool enabled() const;
74+
%Docstring
75+
Enable this item. It will be hidden if disabled.
76+
%End
77+
78+
void setEnabled( bool enabled );
79+
%Docstring
80+
Enable this item. It will be hidden if disabled.
81+
%End
82+
83+
};
84+
85+
/************************************************************************
86+
* This file has been generated automatically from *
87+
* *
88+
* src/gui/qgssnaptogridcanvasitem.h *
89+
* *
90+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
91+
************************************************************************/

python/gui/gui_auto.sip

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
%Include auto_generated/qgssearchquerybuilder.sip
193193
%Include auto_generated/qgsshortcutsmanager.sip
194194
%Include auto_generated/qgsslider.sip
195+
%Include auto_generated/qgssnaptogridcanvasitem.sip
195196
%Include auto_generated/qgsstatusbar.sip
196197
%Include auto_generated/qgssublayersdialog.sip
197198
%Include auto_generated/qgssubstitutionlistwidget.sip

src/gui/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ SET(QGIS_GUI_SRCS
355355
qgsshortcutsmanager.cpp
356356
qgsslider.cpp
357357
qgssnapindicator.cpp
358+
qgssnaptogridcanvasitem.cpp
358359
qgssublayersdialog.cpp
359360
qgssubstitutionlistwidget.cpp
360361
qgssqlcomposerdialog.cpp
@@ -524,6 +525,7 @@ SET(QGIS_GUI_MOC_HDRS
524525
qgssearchquerybuilder.h
525526
qgsshortcutsmanager.h
526527
qgsslider.h
528+
qgssnaptogridcanvasitem.h
527529
qgssqlcomposerdialog.h
528530
qgsstatusbar.h
529531
qgssublayersdialog.h

src/gui/qgssnaptogridcanvasitem.cpp

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#include "qgssnaptogridcanvasitem.h"
2+
#include "qgsmapcanvas.h"
3+
4+
QgsSnapToGridCanvasItem::QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas )
5+
: QgsMapCanvasItem( mapCanvas )
6+
, mGridPen( QPen( QColor( 127, 127, 127, 150 ), 1 ) )
7+
, mCurrentPointPen( QPen( QColor( 200, 200, 200, 150 ), 3 ) )
8+
{
9+
updateMapCanvasCrs();
10+
connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsSnapToGridCanvasItem::updateZoomFactor );
11+
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsSnapToGridCanvasItem::updateMapCanvasCrs );
12+
}
13+
14+
void QgsSnapToGridCanvasItem::paint( QPainter *painter )
15+
{
16+
painter->save();
17+
QgsRectangle mapRect = mMapCanvas->extent();
18+
if ( rect() != mapRect )
19+
setRect( mapRect );
20+
21+
painter->setRenderHints( QPainter::Antialiasing );
22+
painter->setCompositionMode( QPainter::CompositionMode_Difference );
23+
24+
if ( mEnabled && mAvailableByZoomFactor )
25+
{
26+
const QgsRectangle layerExtent = mTransform.transformBoundingBox( mapRect, QgsCoordinateTransform::ReverseTransform );
27+
const QgsPointXY layerPt = mTransform.transform( mPoint, QgsCoordinateTransform::ReverseTransform );
28+
29+
const double gridXMin = std::ceil( layerExtent.xMinimum() / mPrecision ) * mPrecision;
30+
const double gridXMax = std::ceil( layerExtent.xMaximum() / mPrecision ) * mPrecision;
31+
const double gridYMin = std::ceil( layerExtent.yMinimum() / mPrecision ) * mPrecision;
32+
const double gridYMax = std::ceil( layerExtent.yMaximum() / mPrecision ) * mPrecision;
33+
34+
for ( int x = gridXMin ; x < gridXMax; x += mPrecision )
35+
{
36+
for ( int y = gridYMin ; y < gridYMax; y += mPrecision )
37+
{
38+
const QgsPointXY pt = mTransform.transform( x, y );
39+
const QPointF canvasPt = toCanvasCoordinates( pt );
40+
41+
if ( qgsDoubleNear( layerPt.x(), x, mPrecision / 3 ) && qgsDoubleNear( layerPt.y(), y, mPrecision / 3 ) )
42+
{
43+
painter->setPen( mCurrentPointPen );
44+
}
45+
else
46+
{
47+
painter->setPen( mGridPen );
48+
}
49+
painter->drawLine( canvasPt.x() - 3, canvasPt.y(), canvasPt.x() + 3, canvasPt.y() );
50+
painter->drawLine( canvasPt.x(), canvasPt.y() - 3, canvasPt.x(), canvasPt.y() + 3 );
51+
}
52+
}
53+
}
54+
55+
painter->restore();
56+
}
57+
58+
QgsPointXY QgsSnapToGridCanvasItem::point() const
59+
{
60+
return mPoint;
61+
}
62+
63+
void QgsSnapToGridCanvasItem::setPoint( const QgsPointXY &point )
64+
{
65+
mPoint = point;
66+
update();
67+
}
68+
69+
double QgsSnapToGridCanvasItem::precision() const
70+
{
71+
return mPrecision;
72+
}
73+
74+
void QgsSnapToGridCanvasItem::setPrecision( double precision )
75+
{
76+
mPrecision = precision;
77+
updateZoomFactor();
78+
}
79+
80+
QgsCoordinateReferenceSystem QgsSnapToGridCanvasItem::crs() const
81+
{
82+
return mTransform.sourceCrs();
83+
}
84+
85+
void QgsSnapToGridCanvasItem::setCrs( const QgsCoordinateReferenceSystem &crs )
86+
{
87+
mTransform.setSourceCrs( crs );
88+
updateZoomFactor();
89+
}
90+
91+
bool QgsSnapToGridCanvasItem::enabled() const
92+
{
93+
return mEnabled;
94+
}
95+
96+
void QgsSnapToGridCanvasItem::setEnabled( bool enabled )
97+
{
98+
mEnabled = enabled;
99+
update();
100+
}
101+
102+
void QgsSnapToGridCanvasItem::updateMapCanvasCrs()
103+
{
104+
mTransform.setContext( mMapCanvas->mapSettings().transformContext() );
105+
mTransform.setDestinationCrs( mMapCanvas->mapSettings().destinationCrs() );
106+
update();
107+
}
108+
109+
110+
111+
void QgsSnapToGridCanvasItem::updateZoomFactor()
112+
{
113+
if ( !isVisible() )
114+
return;
115+
116+
try
117+
{
118+
const int threshold = 5;
119+
120+
const QgsPointXY centerPoint = mMapCanvas->extent().center();
121+
const QPointF canvasCenter = toCanvasCoordinates( centerPoint );
122+
123+
const QgsPointXY pt1 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( canvasCenter.x() - threshold, canvasCenter.y() - threshold );
124+
const QgsPointXY pt2 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( canvasCenter.x() + threshold, canvasCenter.y() + threshold );
125+
126+
const QgsPointXY layerPt1 = mTransform.transform( pt1, QgsCoordinateTransform::ReverseTransform );
127+
const QgsPointXY layerPt2 = mTransform.transform( pt2, QgsCoordinateTransform::ReverseTransform );
128+
129+
const double dist = layerPt1.distance( layerPt2 );
130+
131+
if ( dist < mPrecision )
132+
mAvailableByZoomFactor = true;
133+
else
134+
mAvailableByZoomFactor = false;
135+
}
136+
catch ( QgsCsException &e )
137+
{
138+
// transform errors?
139+
// you've probably got worse problems than the grid with your digitizing operations in the current projection.
140+
mAvailableByZoomFactor = false;
141+
}
142+
}

src/gui/qgssnaptogridcanvasitem.h

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#ifndef QGSSNAPTOGRIDCANVASITEM_H
2+
#define QGSSNAPTOGRIDCANVASITEM_H
3+
4+
#include <QObject>
5+
#include <QPen>
6+
7+
#include "qgscoordinatereferencesystem.h"
8+
#include "qgsmapcanvasitem.h"
9+
#include "qgscoordinatetransform.h"
10+
11+
/**
12+
* \ingroup gui
13+
*
14+
* Shows a grid on the map canvas given a spatial resolution.
15+
*
16+
* \since QGIS 3.4
17+
*/
18+
class GUI_EXPORT QgsSnapToGridCanvasItem : public QObject, public QgsMapCanvasItem
19+
{
20+
Q_OBJECT
21+
22+
public:
23+
24+
/**
25+
* Will automatically be added to the \a mapCanvas.
26+
*/
27+
QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas );
28+
29+
void paint( QPainter *painter ) override;
30+
31+
/**
32+
* A point that will be highlighted on the map canvas.
33+
* The point needs to be in map coordinates. The closest point on the
34+
* grid will be highlighted.
35+
*/
36+
QgsPointXY point() const;
37+
38+
/**
39+
* A point that will be highlighted on the map canvas.
40+
* The point needs to be in map coordinates. The closest point on the
41+
* grid will be highlighted.
42+
*/
43+
void setPoint( const QgsPointXY &point );
44+
45+
/**
46+
* The resolution of the grid in map units.
47+
* If a crs has been specified it will be in CRS units.
48+
*/
49+
double precision() const;
50+
51+
/**
52+
* The resolution of the grid in map units.
53+
* If a crs has been specified it will be in CRS units.
54+
*/
55+
void setPrecision( double precision );
56+
57+
/**
58+
* The CRS in which the grid should be calculated.
59+
* By default will be an invalid QgsCoordinateReferenceSystem and
60+
* as such equal to the CRS of the map canvas.
61+
*/
62+
QgsCoordinateReferenceSystem crs() const;
63+
64+
/**
65+
* The CRS in which the grid should be calculated.
66+
* By default will be an invalid QgsCoordinateReferenceSystem and
67+
* as such equal to the CRS of the map canvas.
68+
*/
69+
void setCrs( const QgsCoordinateReferenceSystem &crs );
70+
71+
/**
72+
* Enable this item. It will be hidden if disabled.
73+
*/
74+
bool enabled() const;
75+
76+
/**
77+
* Enable this item. It will be hidden if disabled.
78+
*/
79+
void setEnabled( bool enabled );
80+
81+
private slots:
82+
void updateMapCanvasCrs();
83+
84+
void updateZoomFactor();
85+
86+
private:
87+
QPen mGridPen;
88+
QPen mCurrentPointPen;
89+
90+
bool mEnabled = true;
91+
bool mAvailableByZoomFactor = false;
92+
93+
double mPrecision = 0.0;
94+
QgsCoordinateTransform mTransform;
95+
QgsPointXY mPoint;
96+
};
97+
98+
#endif // QGSSNAPTOGRIDCANVASITEM_H

0 commit comments

Comments
 (0)