QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgssnaptogridcanvasitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssnaptogridcanvasitem.cpp
3  ----------------------
4  begin : August 2018
5  copyright : (C) Matthias Kuhn
6  email : [email protected]
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsmapcanvas.h"
18 
20  : QgsMapCanvasItem( mapCanvas )
21 {
22  updateMapCanvasCrs();
23  connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsSnapToGridCanvasItem::updateZoomFactor );
24  connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsSnapToGridCanvasItem::updateMapCanvasCrs );
25 }
26 
27 void QgsSnapToGridCanvasItem::paint( QPainter *painter )
28 {
29  if ( !mEnabled || !mAvailableByZoomFactor )
30  return;
31 
32  QgsScopedQPainterState painterState( painter );
33  QgsRectangle mapRect = mMapCanvas->extent();
34 
35  painter->setRenderHints( QPainter::Antialiasing );
36  painter->setCompositionMode( QPainter::CompositionMode_Difference );
37 
38  double scaleFactor = painter->fontMetrics().xHeight() * .2;
39 
40  mGridPen.setWidth( scaleFactor );
41  mCurrentPointPen.setWidth( scaleFactor * 3 );
42  const int gridMarkerLength = scaleFactor * 3;
43 
44  try
45  {
46  const QgsRectangle layerExtent = mTransform.transformBoundingBox( mapRect, QgsCoordinateTransform::ReverseTransform );
47  const QgsPointXY layerPt = mTransform.transform( mPoint, QgsCoordinateTransform::ReverseTransform );
48 
49  const double gridXMin = std::ceil( layerExtent.xMinimum() / mPrecision ) * mPrecision;
50  const double gridXMax = std::ceil( layerExtent.xMaximum() / mPrecision ) * mPrecision;
51  const double gridYMin = std::ceil( layerExtent.yMinimum() / mPrecision ) * mPrecision;
52  const double gridYMax = std::ceil( layerExtent.yMaximum() / mPrecision ) * mPrecision;
53 
54  for ( double x = gridXMin ; x < gridXMax; x += mPrecision )
55  {
56  for ( double y = gridYMin ; y < gridYMax; y += mPrecision )
57  {
58  const QgsPointXY pt = mTransform.transform( x, y );
59  const QPointF canvasPt = toCanvasCoordinates( pt );
60 
61  if ( qgsDoubleNear( layerPt.x(), x, mPrecision / 2 ) && qgsDoubleNear( layerPt.y(), y, mPrecision / 2 ) )
62  {
63  painter->setPen( mCurrentPointPen );
64  }
65  else
66  {
67  painter->setPen( mGridPen );
68  }
69  painter->drawLine( canvasPt.x() - gridMarkerLength, canvasPt.y(), canvasPt.x() + gridMarkerLength, canvasPt.y() );
70  painter->drawLine( canvasPt.x(), canvasPt.y() - gridMarkerLength, canvasPt.x(), canvasPt.y() + gridMarkerLength );
71 
72  }
73  }
74  }
75  catch ( QgsCsException &e )
76  {
77  Q_UNUSED( e )
78  mAvailableByZoomFactor = false;
79  }
80 }
81 
83 {
84  return mPoint;
85 }
86 
88 {
89  mPoint = point;
90  update();
91 }
92 
94 {
95  return mPrecision;
96 }
97 
99 {
100  mPrecision = precision;
101  updateZoomFactor();
102 }
103 
105 {
106  return mTransform.sourceCrs();
107 }
108 
110 {
111  mTransform.setSourceCrs( crs );
112  updateZoomFactor();
113 }
114 
116 {
117  return mEnabled;
118 }
119 
121 {
122  mEnabled = enabled;
123  update();
124 }
125 
126 void QgsSnapToGridCanvasItem::updateMapCanvasCrs()
127 {
130  update();
131 }
132 
133 
134 
135 void QgsSnapToGridCanvasItem::updateZoomFactor()
136 {
137  if ( !isVisible() )
138  return;
139 
140  try
141  {
142  const int threshold = 5;
143 
144  const QgsRectangle extent = mMapCanvas->extent();
145  if ( extent != rect() )
146  setRect( extent );
147 
148  const QgsPointXY centerPoint = mMapCanvas->extent().center();
149  const QPointF canvasCenter = toCanvasCoordinates( centerPoint );
150 
151  const QgsPointXY pt1 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( static_cast<int>( canvasCenter.x() - threshold ),
152  static_cast<int>( canvasCenter.y() - threshold ) );
153  const QgsPointXY pt2 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( static_cast<int>( canvasCenter.x() + threshold ),
154  static_cast<int>( canvasCenter.y() + threshold ) );
155 
156  const QgsPointXY layerPt1 = mTransform.transform( pt1, QgsCoordinateTransform::ReverseTransform );
157  const QgsPointXY layerPt2 = mTransform.transform( pt2, QgsCoordinateTransform::ReverseTransform );
158 
159  const double dist = layerPt1.distance( layerPt2 );
160 
161  if ( dist < mPrecision )
162  mAvailableByZoomFactor = true;
163  else
164  mAvailableByZoomFactor = false;
165  }
166  catch ( QgsCsException & )
167  {
168  // transform errors?
169  // you've probably got worse problems than the grid with your digitizing operations in the current projection.
170  mAvailableByZoomFactor = false;
171  }
172 }
This class represents a coordinate reference system (CRS).
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source coordinate reference system, which the transform will transform coordinates from.
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
void setContext(const QgsCoordinateTransformContext &context)
Sets the context in which the coordinate transform should be calculated.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source coordinate reference system.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination coordinate reference system.
@ ReverseTransform
Transform from destination to source CRS.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
An abstract class for items that can be placed on the map canvas.
QgsRectangle rect() const
returns canvas item rectangle in map units
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
QgsMapCanvas * mMapCanvas
pointer to map canvas
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:86
void extentsChanged()
Emitted when the extents of the map change.
void destinationCrsChanged()
Emitted when map CRS has changed.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
const QgsMapToPixel & mapToPixel() const
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
A class to represent a 2D point.
Definition: qgspointxy.h:44
double y
Definition: qgspointxy.h:48
Q_GADGET double x
Definition: qgspointxy.h:47
double distance(double x, double y) const SIP_HOLDGIL
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:196
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
Scoped object for saving and restoring a QPainter object's state.
bool enabled() const
Enable this item.
double precision() const
The resolution of the grid in map units.
void setCrs(const QgsCoordinateReferenceSystem &crs)
The CRS in which the grid should be calculated.
void setPoint(const QgsPointXY &point)
A point that will be highlighted on the map canvas.
void setEnabled(bool enabled)
Enable this item.
QgsSnapToGridCanvasItem(QgsMapCanvas *mapCanvas)
Will automatically be added to the mapCanvas.
void paint(QPainter *painter) override
function to be implemented by derived classes
QgsCoordinateReferenceSystem crs() const
The CRS in which the grid should be calculated.
void setPrecision(double precision)
The resolution of the grid in map units.
QgsPointXY point() const
A point that will be highlighted on the map canvas.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
const QgsCoordinateReferenceSystem & crs
int precision