QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
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 
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 
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 }
void set(double x, double y)
Sets the x and y value of the point.
Definition: qgspointxy.h:119
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
double mapRotation() const
Returns current map rotation in degrees.
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
int mapWidth() const
Returns current map width in pixels The information is only known if setRotation was used...
int mapHeight() const
Returns current map height in pixels.
static QgsMapToPixel fromScale(double scale, QgsUnitTypes::DistanceUnit mapUnits, double dpi=96)
Returns a new QgsMapToPixel created using a specified scale and distance unit.
QgsMapToPixel()
Constructor.
QString showParameters() const
String representation of the parameters used in the transform.
double mapUnitsPerPixel() const
Returns current map units per pixel.
double x
Definition: qgspointxy.h:47
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:54
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Set parameters for use in transforming coordinates.
Q_DECL_DEPRECATED QgsPointXY toMapPoint(double x, double y) const
Transform device coordinates to map (world) coordinates.
QTransform transform() const
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
void setMapUnitsPerPixel(double mapUnitsPerPixel)
Set map units per pixel.
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.