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