QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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 #include "qgsunittypes.h"
19 
20 #include <QPoint>
21 #include <QTextStream>
22 #include <QVector>
23 #include <QTransform>
24 
25 QgsMapToPixel::QgsMapToPixel( double mapUnitsPerPixel,
26  double xc,
27  double yc,
28  int width,
29  int height,
30  double rotation )
31  : mValid( true )
32  , mMapUnitsPerPixel( mapUnitsPerPixel )
33  , mWidth( width )
34  , mHeight( height )
35  , mRotation( rotation )
36  , mXCenter( xc )
37  , mYCenter( yc )
38  , mXMin( xc - ( mWidth * mMapUnitsPerPixel / 2.0 ) )
39  , mYMin( yc - ( mHeight * mMapUnitsPerPixel / 2.0 ) )
40 {
41  Q_ASSERT( mapUnitsPerPixel > 0 );
42  updateMatrix();
43 }
44 
45 QgsMapToPixel::QgsMapToPixel( double mapUnitsPerPixel )
46  : mValid( true )
47  , mMapUnitsPerPixel( mapUnitsPerPixel )
48  , mWidth( 0 )
49  , mHeight( 0 )
50  , mXCenter( 0 )
51  , mYCenter( 0 )
52 {
53  updateMatrix();
54 }
55 
56 QgsMapToPixel QgsMapToPixel::fromScale( double scale, Qgis::DistanceUnit mapUnits, double dpi )
57 {
58  const double metersPerPixel = 25.4 / dpi / 1000.0;
59  const double mapUnitsPerPixel = metersPerPixel * QgsUnitTypes::fromUnitToUnitFactor( Qgis::DistanceUnit::Meters, mapUnits );
60  return QgsMapToPixel( mapUnitsPerPixel * scale );
61 }
62 
64 {
65  updateMatrix();
66 }
67 
68 bool QgsMapToPixel::updateMatrix()
69 {
70  const QTransform newMatrix = transform();
71 
72  // https://github.com/qgis/QGIS/issues/20856
73  if ( !newMatrix.isInvertible() )
74  return false;
75 
76  mMatrix = newMatrix;
77  return true;
78 }
79 
80 void QgsMapToPixel::setMapUnitsPerPixel( double mapUnitsPerPixel )
81 {
82  mValid = true;
83 
84  const double oldUnits = mMapUnitsPerPixel;
85  mMapUnitsPerPixel = mapUnitsPerPixel;
86  if ( !updateMatrix() )
87  {
88  mMapUnitsPerPixel = oldUnits;
89  }
90 }
91 
92 void QgsMapToPixel::setMapRotation( double degrees, double cx, double cy )
93 {
94  mValid = true;
95 
96  const double oldRotation = mRotation;
97  const double oldXCenter = mXCenter;
98  const double oldYCenter = mYCenter;
99  const double oldWidth = mWidth;
100 
101  mRotation = degrees;
102  mXCenter = cx;
103  mYCenter = cy;
104  if ( mWidth < 0 )
105  {
106  // set width not that we can compute it
107  mWidth = ( ( mXCenter - mXMin ) * 2 ) / mMapUnitsPerPixel;
108  }
109 
110  if ( !updateMatrix() )
111  {
112  mRotation = oldRotation;
113  mXCenter = oldXCenter;
114  mYCenter = oldYCenter;
115  mWidth = oldWidth;
116  }
117 }
118 
119 void QgsMapToPixel::setParameters( double mapUnitsPerPixel,
120  double xc,
121  double yc,
122  int width,
123  int height,
124  double rotation,
125  bool *ok )
126 {
127  mValid = true;
128 
129  const double oldMUPP = mMapUnitsPerPixel;
130  const double oldXCenter = mXCenter;
131  const double oldYCenter = mYCenter;
132  const double oldWidth = mWidth;
133  const double oldHeight = mHeight;
134  const double oldRotation = mRotation;
135  const double oldXMin = mXMin;
136  const double oldYMin = mYMin;
137 
138  mMapUnitsPerPixel = mapUnitsPerPixel;
139  mXCenter = xc;
140  mYCenter = yc;
141  mWidth = width;
142  mHeight = height;
143  mRotation = rotation;
144  mXMin = xc - ( mWidth * mMapUnitsPerPixel / 2.0 );
145  mYMin = yc - ( mHeight * mMapUnitsPerPixel / 2.0 );
146 
147  if ( !updateMatrix() )
148  {
149  mMapUnitsPerPixel = oldMUPP;
150  mXCenter = oldXCenter;
151  mYCenter = oldYCenter;
152  mWidth = oldWidth;
153  mHeight = oldHeight;
154  mRotation = oldRotation;
155  mXMin = oldXMin;
156  mYMin = oldYMin;
157  *ok = false;
158  }
159  else
160  {
161  *ok = true;
162  }
163 }
164 
165 void QgsMapToPixel::setParameters( double mapUnitsPerPixel,
166  double xc,
167  double yc,
168  int width,
169  int height,
170  double rotation )
171 {
172  mValid = true;
173  bool ok;
174  setParameters( mapUnitsPerPixel, xc, yc, width, height, rotation, &ok );
175 }
176 
178 {
179  QString rep;
180  QTextStream( &rep ) << "Map units/pixel: " << mMapUnitsPerPixel
181  << " center: " << mXCenter << ',' << mYCenter
182  << " rotation: " << mRotation
183  << " size: " << mWidth << 'x' << mHeight;
184  return rep;
185 }
186 
187 QTransform QgsMapToPixel::transform() const
188 {
189  // NOTE: operations are done in the reverse order in which
190  // they are configured, so translation to geographical
191  // center happens first, then scaling, then rotation
192  // and finally translation to output viewport center
193 
194  const double rotation = mapRotation();
195  if ( qgsDoubleNear( rotation, 0.0 ) )
196  {
197  //no rotation, return a simplified matrix
198  return QTransform::fromScale( 1.0 / mMapUnitsPerPixel, -1.0 / mMapUnitsPerPixel )
199  .translate( -mXMin, - ( mYMin + mHeight * mMapUnitsPerPixel ) );
200  }
201  else
202  {
203  const double cy = mapHeight() / 2.0;
204  const double cx = mapWidth() / 2.0;
205  return QTransform::fromTranslate( cx, cy )
206  .rotate( rotation )
207  .scale( 1 / mMapUnitsPerPixel, -1 / mMapUnitsPerPixel )
208  .translate( -mXCenter, -mYCenter );
209  }
210 }
211 
DistanceUnit
Units of distance.
Definition: qgis.h:4090
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)
Sets the map units per pixel.
void setMapRotation(double degrees, double cx, double cy)
Sets map rotation in degrees (clockwise).
QgsMapToPixel()
Constructor for an invalid QgsMapToPixel.
double mapUnitsPerPixel() const
Returns the current map units per pixel.
static QgsMapToPixel fromScale(double scale, Qgis::DistanceUnit mapUnits, double dpi=96)
Returns a new QgsMapToPixel created using a specified scale and distance unit.
QTransform transform() const
Returns a QTransform encapsulating the map to pixel conversion.
int mapWidth() const
Returns the current map width in pixels.
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Sets parameters for use in transforming coordinates.
QString showParameters() const
Returns a string representation of the parameters used in the transform.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::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:5172