QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
28QgsMapToPixel::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
48QgsMapToPixel::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
71bool 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
83void 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
95void 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
122void 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
168void 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
190QTransform 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:2527