QGIS API Documentation  3.20.0-Odense (decaadbb31)
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  , mXMin( xc - ( mWidth * mMapUnitsPerPixel / 2.0 ) )
41  , mYMin( 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 
69 bool QgsMapToPixel::updateMatrix()
70 {
71  QTransform newMatrix = transform();
72 
73  // https://github.com/qgis/QGIS/issues/20856
74  if ( !newMatrix.isInvertible() )
75  return false;
76 
77  mMatrix = newMatrix;
78  return true;
79 }
80 
81 void QgsMapToPixel::setMapUnitsPerPixel( double mapUnitsPerPixel )
82 {
83  double oldUnits = mMapUnitsPerPixel;
84  mMapUnitsPerPixel = mapUnitsPerPixel;
85  if ( !updateMatrix() )
86  {
87  mMapUnitsPerPixel = oldUnits;
88  }
89 }
90 
91 void QgsMapToPixel::setMapRotation( double degrees, double cx, double cy )
92 {
93  double oldRotation = mRotation;
94  double oldXCenter = mXCenter;
95  double oldYCenter = mYCenter;
96  double oldWidth = mWidth;
97 
98  mRotation = degrees;
99  mXCenter = cx;
100  mYCenter = cy;
101  if ( mWidth < 0 )
102  {
103  // set width not that we can compute it
104  mWidth = ( ( mXCenter - mXMin ) * 2 ) / mMapUnitsPerPixel;
105  }
106 
107  if ( !updateMatrix() )
108  {
109  mRotation = oldRotation;
110  mXCenter = oldXCenter;
111  mYCenter = oldYCenter;
112  mWidth = oldWidth;
113  }
114 }
115 
116 void QgsMapToPixel::setParameters( double mapUnitsPerPixel,
117  double xc,
118  double yc,
119  int width,
120  int height,
121  double rotation,
122  bool *ok )
123 {
124  double oldMUPP = mMapUnitsPerPixel;
125  double oldXCenter = mXCenter;
126  double oldYCenter = mYCenter;
127  double oldWidth = mWidth;
128  double oldHeight = mHeight;
129  double oldRotation = mRotation;
130  double oldXMin = mXMin;
131  double oldYMin = mYMin;
132 
133  mMapUnitsPerPixel = mapUnitsPerPixel;
134  mXCenter = xc;
135  mYCenter = yc;
136  mWidth = width;
137  mHeight = height;
138  mRotation = rotation;
139  mXMin = xc - ( mWidth * mMapUnitsPerPixel / 2.0 );
140  mYMin = yc - ( mHeight * mMapUnitsPerPixel / 2.0 );
141 
142  if ( !updateMatrix() )
143  {
144  mMapUnitsPerPixel = oldMUPP;
145  mXCenter = oldXCenter;
146  mYCenter = oldYCenter;
147  mWidth = oldWidth;
148  mHeight = oldHeight;
149  mRotation = oldRotation;
150  mXMin = oldXMin;
151  mYMin = oldYMin;
152  *ok = false;
153  }
154  else
155  {
156  *ok = true;
157  }
158 }
159 
160 void QgsMapToPixel::setParameters( double mapUnitsPerPixel,
161  double xc,
162  double yc,
163  int width,
164  int height,
165  double rotation )
166 {
167  bool ok;
168  setParameters( mapUnitsPerPixel, xc, yc, width, height, rotation, &ok );
169 }
170 
172 {
173  QString rep;
174  QTextStream( &rep ) << "Map units/pixel: " << mMapUnitsPerPixel
175  << " center: " << mXCenter << ',' << mYCenter
176  << " rotation: " << mRotation
177  << " size: " << mWidth << 'x' << mHeight;
178  return rep;
179 }
180 
181 QTransform QgsMapToPixel::transform() const
182 {
183  // NOTE: operations are done in the reverse order in which
184  // they are configured, so translation to geographical
185  // center happens first, then scaling, then rotation
186  // and finally translation to output viewport center
187 
188  double rotation = mapRotation();
189  if ( qgsDoubleNear( rotation, 0.0 ) )
190  {
191  //no rotation, return a simplified matrix
192  return QTransform::fromScale( 1.0 / mMapUnitsPerPixel, -1.0 / mMapUnitsPerPixel )
193  .translate( -mXMin, - ( mYMin + mHeight * mMapUnitsPerPixel ) );
194  }
195  else
196  {
197  double cy = mapHeight() / 2.0;
198  double cx = mapWidth() / 2.0;
199  return QTransform::fromTranslate( cx, cy )
200  .rotate( rotation )
201  .scale( 1 / mMapUnitsPerPixel, -1 / mMapUnitsPerPixel )
202  .translate( -mXCenter, -mYCenter );
203  }
204 }
205 
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
int mapHeight() const
Returns current map height in pixels.
void setMapUnitsPerPixel(double mapUnitsPerPixel)
Set map units per pixel.
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
QgsMapToPixel()
Constructor.
double mapUnitsPerPixel() const
Returns current map units per pixel.
QTransform transform() const
Returns a QTransform encapsulating the map to pixel conversion.
int mapWidth() const
Returns current map width in pixels The information is only known if setRotation was used.
double mapRotation() const
Returns current map rotation in degrees (clockwise)
static QgsMapToPixel fromScale(double scale, QgsUnitTypes::DistanceUnit mapUnits, double dpi=96)
Returns a new QgsMapToPixel created using a specified scale and distance unit.
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Set parameters for use in transforming coordinates.
QString showParameters() const
String representation of the parameters used in the transform.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance 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:598