QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsmaptopixel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaptopixel.cpp - description
3  -------------------
4  begin : Sat Jun 22 2002
5  copyright : (C) 2002 by Gary E.Sherman
6  email : sherman at mrcc.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include "qgsmaptopixel.h"
18 
19 #include <QPoint>
20 #include <QTextStream>
21 #include <QVector>
22 #include <QTransform>
23 
24 #include "qgslogger.h"
25 #include "qgspointxy.h"
26 
27 
28 QgsMapToPixel::QgsMapToPixel( double mapUnitsPerPixel,
29  double xc,
30  double yc,
31  int width,
32  int height,
33  double rotation )
34  : mMapUnitsPerPixel( mapUnitsPerPixel )
35  , mWidth( width )
36  , mHeight( height )
37  , mRotation( rotation )
38  , mXCenter( xc )
39  , mYCenter( yc )
40  , xMin( xc - ( mWidth * mMapUnitsPerPixel / 2.0 ) )
41  , yMin( yc - ( mHeight * mMapUnitsPerPixel / 2.0 ) )
42 {
43  Q_ASSERT( mapUnitsPerPixel > 0 );
44  updateMatrix();
45 }
46 
47 QgsMapToPixel::QgsMapToPixel( double mapUnitsPerPixel )
48  : mMapUnitsPerPixel( mapUnitsPerPixel )
49  , mWidth( 0 )
50  , mHeight( 0 )
51  , mXCenter( 0 )
52  , mYCenter( 0 )
53 {
54  updateMatrix();
55 }
56 
58 {
59  double metersPerPixel = 25.4 / dpi / 1000.0;
61  return QgsMapToPixel( mapUnitsPerPixel * scale );
62 }
63 
65 {
66  updateMatrix();
67 }
68 
70 {
71  return mHeight;
72 }
73 
75 {
76  return mWidth;
77 }
78 
79 bool QgsMapToPixel::updateMatrix()
80 {
81  QTransform newMatrix = transform();
82 
83  // https://github.com/qgis/QGIS/issues/20856
84  if ( !newMatrix.isInvertible() )
85  return false;
86 
87  mMatrix = newMatrix;
88  return true;
89 }
90 
91 QgsPointXY QgsMapToPixel::toMapCoordinates( double x, double y ) const
92 {
93  bool invertible;
94  QTransform matrix = mMatrix.inverted( &invertible );
95  assert( invertible );
96  qreal mx, my;
97  qreal x_qreal = x, y_qreal = y;
98  matrix.map( x_qreal, y_qreal, &mx, &my );
99  return QgsPointXY( mx, my );
100 }
101 
103 {
104  QgsPointXY mapPt = toMapCoordinates( static_cast<double>( p.x() ), static_cast<double>( p.y() ) );
105  return QgsPointXY( mapPt );
106 }
107 
109 {
110  return toMapCoordinates( static_cast<double>( x ), static_cast<double>( y ) );
111 }
112 
113 QgsPointXY QgsMapToPixel::toMapPoint( double x, double y ) const
114 {
115  return toMapCoordinates( x, y );
116 }
117 
118 void QgsMapToPixel::setMapUnitsPerPixel( double mapUnitsPerPixel )
119 {
120  double oldUnits = mMapUnitsPerPixel;
121  mMapUnitsPerPixel = mapUnitsPerPixel;
122  if ( !updateMatrix() )
123  {
124  mMapUnitsPerPixel = oldUnits;
125  }
126 }
127 
129 {
130  return mMapUnitsPerPixel;
131 }
132 
133 void QgsMapToPixel::setMapRotation( double degrees, double cx, double cy )
134 {
135  double oldRotation = mRotation;
136  double oldXCenter = mXCenter;
137  double oldYCenter = mYCenter;
138  double oldWidth = mWidth;
139 
140  mRotation = degrees;
141  mXCenter = cx;
142  mYCenter = cy;
143  if ( mWidth < 0 )
144  {
145  // set width not that we can compute it
146  mWidth = ( ( mXCenter - xMin ) * 2 ) / mMapUnitsPerPixel;
147  }
148 
149  if ( !updateMatrix() )
150  {
151  mRotation = oldRotation;
152  mXCenter = oldXCenter;
153  mYCenter = oldYCenter;
154  mWidth = oldWidth;
155  }
156 }
157 
159 {
160  return mRotation;
161 }
162 
163 void QgsMapToPixel::setParameters( double mapUnitsPerPixel,
164  double xc,
165  double yc,
166  int width,
167  int height,
168  double rotation )
169 {
170  double oldMUPP = mMapUnitsPerPixel;
171  double oldXCenter = mXCenter;
172  double oldYCenter = mYCenter;
173  double oldWidth = mWidth;
174  double oldHeight = mHeight;
175  double oldRotation = mRotation;
176  double oldXMin = xMin;
177  double oldYMin = yMin;
178 
179  mMapUnitsPerPixel = mapUnitsPerPixel;
180  mXCenter = xc;
181  mYCenter = yc;
182  mWidth = width;
183  mHeight = height;
184  mRotation = rotation;
185  xMin = xc - ( mWidth * mMapUnitsPerPixel / 2.0 );
186  yMin = yc - ( mHeight * mMapUnitsPerPixel / 2.0 );
187 
188  if ( !updateMatrix() )
189  {
190  mMapUnitsPerPixel = oldMUPP;
191  mXCenter = oldXCenter;
192  mYCenter = oldYCenter;
193  mWidth = oldWidth;
194  mHeight = oldHeight;
195  mRotation = oldRotation;
196  xMin = oldXMin;
197  yMin = oldYMin;
198  }
199 }
200 
202 {
203  QString rep;
204  QTextStream( &rep ) << "Map units/pixel: " << mMapUnitsPerPixel
205  << " center: " << mXCenter << ',' << mYCenter
206  << " rotation: " << mRotation
207  << " size: " << mWidth << 'x' << mHeight;
208  return rep;
209 }
210 
211 QgsPointXY QgsMapToPixel::transform( qreal x, qreal y ) const
212 {
213  transformInPlace( x, y );
214  return QgsPointXY( x, y );
215 }
216 
218 {
219  qreal x = p.x(), y = p.y();
220  transformInPlace( x, y );
221 // QgsDebugMsg(QString("Point to pixel...X : %1-->%2, Y: %3 -->%4").arg(p.x()).arg(dx).arg(p.y()).arg(dy));
222  return QgsPointXY( x, y );
223 }
224 
226 {
227  qreal x = p->x(), y = p->y();
228  transformInPlace( x, y );
229 // QgsDebugMsg(QString("Point to pixel...X : %1-->%2, Y: %3 -->%4").arg(p->x()).arg(x).arg(p->y()).arg(y));
230  p->set( x, y );
231 }
232 
233 void QgsMapToPixel::transformInPlace( double &x, double &y ) const
234 {
235  // Map 2 Pixel
236  qreal mx, my;
237  qreal x_qreal = x, y_qreal = y;
238  mMatrix.map( x_qreal, y_qreal, &mx, &my );
239  //QgsDebugMsg(QString("XXX transformInPlace X : %1-->%2, Y: %3 -->%4").arg(x).arg(mx).arg(y).arg(my));
240  x = mx;
241  y = my;
242 }
243 
244 void QgsMapToPixel::transformInPlace( float &x, float &y ) const
245 {
246  double mx = x, my = y;
247  transformInPlace( mx, my );
248  x = mx;
249  y = my;
250 }
251 
252 QTransform QgsMapToPixel::transform() const
253 {
254  // NOTE: operations are done in the reverse order in which
255  // they are configured, so translation to geographical
256  // center happens first, then scaling, then rotation
257  // and finally translation to output viewport center
258 
259  double rotation = mapRotation();
260  if ( qgsDoubleNear( rotation, 0.0 ) )
261  {
262  //no rotation, return a simplified matrix
263  return QTransform::fromScale( 1.0 / mMapUnitsPerPixel, -1.0 / mMapUnitsPerPixel )
264  .translate( -xMin, - ( yMin + mHeight * mMapUnitsPerPixel ) );
265  }
266  else
267  {
268  double cy = mapHeight() / 2.0;
269  double cx = mapWidth() / 2.0;
270  return QTransform::fromTranslate( cx, cy )
271  .rotate( rotation )
272  .scale( 1 / mMapUnitsPerPixel, -1 / mMapUnitsPerPixel )
273  .translate( -mXCenter, -mYCenter );
274  }
275 }
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns current map units per pixel.
Definition: qgsmaptopixel.cpp:128
QgsMapToPixel::setParameters
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Set parameters for use in transforming coordinates.
Definition: qgsmaptopixel.cpp:163
qgsmaptopixel.h
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
QgsMapToPixel::toMapCoordinates
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
Definition: qgsmaptopixel.cpp:108
QgsPointXY::set
void set(double x, double y) SIP_HOLDGIL
Sets the x and y value of the point.
Definition: qgspointxy.h:124
QgsUnitTypes::fromUnitToUnitFactor
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
Definition: qgsunittypes.cpp:352
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsMapToPixel::mapHeight
int mapHeight() const
Returns current map height in pixels.
Definition: qgsmaptopixel.cpp:69
QgsMapToPixel::mapRotation
double mapRotation() const
Returns current map rotation in degrees (clockwise)
Definition: qgsmaptopixel.cpp:158
QgsUnitTypes::DistanceMeters
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
QgsMapToPixel::toMapPoint
Q_DECL_DEPRECATED QgsPointXY toMapPoint(double x, double y) const
Transform device coordinates to map (world) coordinates.
Definition: qgsmaptopixel.cpp:113
QgsMapToPixel::showParameters
QString showParameters() const
String representation of the parameters used in the transform.
Definition: qgsmaptopixel.cpp:201
QgsMapToPixel::QgsMapToPixel
QgsMapToPixel()
Constructor.
Definition: qgsmaptopixel.cpp:64
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsMapToPixel::transformInPlace
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
Definition: qgsmaptopixel.cpp:233
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsMapToPixel::mapWidth
int mapWidth() const
Returns current map width in pixels The information is only known if setRotation was used.
Definition: qgsmaptopixel.cpp:74
QgsMapToPixel::transform
QTransform transform() const
Definition: qgsmaptopixel.cpp:252
qgslogger.h
QgsMapToPixel::fromScale
static QgsMapToPixel fromScale(double scale, QgsUnitTypes::DistanceUnit mapUnits, double dpi=96)
Returns a new QgsMapToPixel created using a specified scale and distance unit.
Definition: qgsmaptopixel.cpp:57
QgsMapToPixel::setMapRotation
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
Definition: qgsmaptopixel.cpp:133
qgspointxy.h
QgsMapToPixel::setMapUnitsPerPixel
void setMapUnitsPerPixel(double mapUnitsPerPixel)
Set map units per pixel.
Definition: qgsmaptopixel.cpp:118