QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  painter->save();
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  painter->restore();
82 }
83 
85 {
86  return mPoint;
87 }
88 
90 {
91  mPoint = point;
92  update();
93 }
94 
96 {
97  return mPrecision;
98 }
99 
101 {
102  mPrecision = precision;
103  updateZoomFactor();
104 }
105 
107 {
108  return mTransform.sourceCrs();
109 }
110 
112 {
113  mTransform.setSourceCrs( crs );
114  updateZoomFactor();
115 }
116 
118 {
119  return mEnabled;
120 }
121 
123 {
124  mEnabled = enabled;
125  update();
126 }
127 
128 void QgsSnapToGridCanvasItem::updateMapCanvasCrs()
129 {
132  update();
133 }
134 
135 
136 
137 void QgsSnapToGridCanvasItem::updateZoomFactor()
138 {
139  if ( !isVisible() )
140  return;
141 
142  try
143  {
144  const int threshold = 5;
145 
146  const QgsRectangle extent = mMapCanvas->extent();
147  if ( extent != rect() )
148  setRect( extent );
149 
150  const QgsPointXY centerPoint = mMapCanvas->extent().center();
151  const QPointF canvasCenter = toCanvasCoordinates( centerPoint );
152 
153  const QgsPointXY pt1 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( static_cast<int>( canvasCenter.x() - threshold ),
154  static_cast<int>( canvasCenter.y() - threshold ) );
155  const QgsPointXY pt2 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( static_cast<int>( canvasCenter.x() + threshold ),
156  static_cast<int>( canvasCenter.y() + threshold ) );
157 
158  const QgsPointXY layerPt1 = mTransform.transform( pt1, QgsCoordinateTransform::ReverseTransform );
159  const QgsPointXY layerPt2 = mTransform.transform( pt2, QgsCoordinateTransform::ReverseTransform );
160 
161  const double dist = layerPt1.distance( layerPt2 );
162 
163  if ( dist < mPrecision )
164  mAvailableByZoomFactor = true;
165  else
166  mAvailableByZoomFactor = false;
167  }
168  catch ( QgsCsException &e )
169  {
170  // transform errors?
171  // you've probably got worse problems than the grid with your digitizing operations in the current projection.
172  mAvailableByZoomFactor = false;
173  }
174 }
A rectangle specified with double values.
Definition: qgsrectangle.h:40
QgsPointXY point() const
A point that will be highlighted on the map canvas.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:190
void setCrs(const QgsCoordinateReferenceSystem &crs)
The CRS in which the grid should be calculated.
void setContext(const QgsCoordinateTransformContext &context)
Sets the context in which the coordinate transform should be calculated.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
QgsSnapToGridCanvasItem(QgsMapCanvas *mapCanvas)
Will automatically be added to the mapCanvas.
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source coordinate reference system, which the transform will transform coordinates from...
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
double precision() const
The resolution of the grid in map units.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:278
An abstract class for items that can be placed on the map canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
const QgsMapToPixel & mapToPixel() const
QgsRectangle rect() const
returns canvas item rectangle in map units
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
void setPrecision(double precision)
The resolution of the grid in map units.
QgsCoordinateReferenceSystem crs() const
The CRS in which the grid should be calculated.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination coordinate reference system.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:229
void setEnabled(bool enabled)
Enable this item.
void destinationCrsChanged()
Emitted when map CRS has changed.
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
double x
Definition: qgspointxy.h:47
void paint(QPainter *painter) override
function to be implemented by derived classes
void setPoint(const QgsPointXY &point)
A point that will be highlighted on the map canvas.
Transform from destination to source CRS.
QgsMapCanvas * mMapCanvas
pointer to map canvas
This class represents a coordinate reference system (CRS).
bool enabled() const
Enable this item.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source coordinate reference system.
void extentsChanged()
Emitted when the extents of the map change.
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.