QGIS API Documentation  2.99.0-Master (a411669)
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://issues.qgis.org/issues/12757
84  if ( !newMatrix.isInvertible() )
85  return false;
86 
87  mMatrix = newMatrix;
88  return true;
89 }
90 
91 QgsPointXY QgsMapToPixel::toMapPoint( 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  //QgsDebugMsg(QString("XXX toMapPoint x:%1 y:%2 -> x:%3 y:%4").arg(x).arg(y).arg(mx).arg(my));
100  return QgsPointXY( mx, my );
101 }
102 
104 {
105  QgsPointXY mapPt = toMapPoint( p.x(), p.y() );
106  return QgsPointXY( mapPt );
107 }
108 
110 {
111  return toMapPoint( x, y );
112 }
113 
114 QgsPointXY QgsMapToPixel::toMapCoordinatesF( double x, double y ) const
115 {
116  return toMapPoint( x, y );
117 }
118 
120 {
121  double oldUnits = mMapUnitsPerPixel;
122  mMapUnitsPerPixel = mapUnitsPerPixel;
123  if ( !updateMatrix() )
124  {
125  mMapUnitsPerPixel = oldUnits;
126  }
127 }
128 
130 {
131  return mMapUnitsPerPixel;
132 }
133 
134 void QgsMapToPixel::setMapRotation( double degrees, double cx, double cy )
135 {
136  double oldRotation = mRotation;
137  double oldXCenter = mXCenter;
138  double oldYCenter = mYCenter;
139  double oldWidth = mWidth;
140 
141  mRotation = degrees;
142  mXCenter = cx;
143  mYCenter = cy;
144  if ( mWidth < 0 )
145  {
146  // set width not that we can compute it
147  mWidth = ( ( mXCenter - xMin ) * 2 ) / mMapUnitsPerPixel;
148  }
149 
150  if ( !updateMatrix() )
151  {
152  mRotation = oldRotation;
153  mXCenter = oldXCenter;
154  mYCenter = oldYCenter;
155  mWidth = oldWidth;
156  }
157 }
158 
160 {
161  return mRotation;
162 }
163 
165  double xc,
166  double yc,
167  int width,
168  int height,
169  double rotation )
170 {
171  double oldMUPP = mMapUnitsPerPixel;
172  double oldXCenter = mXCenter;
173  double oldYCenter = mYCenter;
174  double oldWidth = mWidth;
175  double oldHeight = mHeight;
176  double oldRotation = mRotation;
177  double oldXMin = xMin;
178  double oldYMin = yMin;
179 
180  mMapUnitsPerPixel = mapUnitsPerPixel;
181  mXCenter = xc;
182  mYCenter = yc;
183  mWidth = width;
184  mHeight = height;
185  mRotation = rotation;
186  xMin = xc - ( mWidth * mMapUnitsPerPixel / 2.0 );
187  yMin = yc - ( mHeight * mMapUnitsPerPixel / 2.0 );
188 
189  if ( !updateMatrix() )
190  {
191  mMapUnitsPerPixel = oldMUPP;
192  mXCenter = oldXCenter;
193  mYCenter = oldYCenter;
194  mWidth = oldWidth;
195  mHeight = oldHeight;
196  mRotation = oldRotation;
197  xMin = oldXMin;
198  yMin = oldYMin;
199  }
200 }
201 
203 {
204  QString rep;
205  QTextStream( &rep ) << "Map units/pixel: " << mMapUnitsPerPixel
206  << " center: " << mXCenter << ',' << mYCenter
207  << " rotation: " << mRotation
208  << " size: " << mWidth << 'x' << mHeight;
209  return rep;
210 }
211 
212 QgsPointXY QgsMapToPixel::transform( qreal x, qreal y ) const
213 {
214  transformInPlace( x, y );
215  return QgsPointXY( x, y );
216 }
217 
219 {
220  qreal x = p.x(), y = p.y();
221  transformInPlace( x, y );
222 // QgsDebugMsg(QString("Point to pixel...X : %1-->%2, Y: %3 -->%4").arg(p.x()).arg(dx).arg(p.y()).arg(dy));
223  return QgsPointXY( x, y );
224 }
225 
227 {
228  qreal x = p->x(), y = p->y();
229  transformInPlace( x, y );
230 // QgsDebugMsg(QString("Point to pixel...X : %1-->%2, Y: %3 -->%4").arg(p->x()).arg(x).arg(p->y()).arg(y));
231  p->set( x, y );
232 }
233 
234 void QgsMapToPixel::transformInPlace( double &x, double &y ) const
235 {
236  // Map 2 Pixel
237  qreal mx, my;
238  qreal x_qreal = x, y_qreal = y;
239  mMatrix.map( x_qreal, y_qreal, &mx, &my );
240  //QgsDebugMsg(QString("XXX transformInPlace X : %1-->%2, Y: %3 -->%4").arg(x).arg(mx).arg(y).arg(my));
241  x = mx;
242  y = my;
243 }
244 
245 void QgsMapToPixel::transformInPlace( float &x, float &y ) const
246 {
247  double mx = x, my = y;
248  transformInPlace( mx, my );
249  x = mx;
250  y = my;
251 }
252 
253 QTransform QgsMapToPixel::transform() const
254 {
255  // NOTE: operations are done in the reverse order in which
256  // they are configured, so translation to geographical
257  // center happens first, then scaling, then rotation
258  // and finally translation to output viewport center
259 
260  double rotation = mapRotation();
261  if ( qgsDoubleNear( rotation, 0.0 ) )
262  {
263  //no rotation, return a simplified matrix
264  return QTransform::fromScale( 1.0 / mMapUnitsPerPixel, -1.0 / mMapUnitsPerPixel )
265  .translate( -xMin, - ( yMin + mHeight * mMapUnitsPerPixel ) );
266  }
267  else
268  {
269  double cy = mapHeight() / 2.0;
270  double cx = mapWidth() / 2.0;
271  return QTransform::fromTranslate( cx, cy )
272  .rotate( rotation )
273  .scale( 1 / mMapUnitsPerPixel, -1 / mMapUnitsPerPixel )
274  .translate( -mXCenter, -mYCenter );
275  }
276 }
void set(double x, double y)
Sets the x and y value of the point.
Definition: qgspointxy.h:120
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 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:227
double mapRotation() const
Return 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:36
int mapWidth() const
Return current map width in pixels The information is only known if setRotation was used...
int mapHeight() const
Return 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
Return current map units per pixel.
double x
Definition: qgspointxy.h:47
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:43
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Set parameters for use in transforming coordinates.
QgsPointXY toMapPoint(double x, double y) const
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 toMapCoordinatesF(double x, double y) const
Transform device coordinates to map (world) coordinates.
QgsPointXY toMapCoordinates(int x, int y) const