QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
qgscrsdefinitionwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscrsdefinitionwidget.cpp
3 ---------------------
4 begin : December 2021
5 copyright : (C) 2021 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "moc_qgscrsdefinitionwidget.cpp"
19#include "qgsprojutils.h"
20
21#include <QMessageBox>
22#include <QRegularExpression>
23#include <QRegularExpressionMatch>
24#include <proj.h>
25
27 : QWidget( parent )
28{
29 setupUi( this );
30
31 connect( mButtonCalculate, &QPushButton::clicked, this, &QgsCrsDefinitionWidget::pbnCalculate_clicked );
32 connect( mButtonCopyCRS, &QPushButton::clicked, this, &QgsCrsDefinitionWidget::pbnCopyCRS_clicked );
33 connect( mButtonValidate, &QPushButton::clicked, this, &QgsCrsDefinitionWidget::validateCurrent );
34
35 mFormatComboBox->addItem( tr( "WKT (Recommended)" ), static_cast< int >( Qgis::CrsDefinitionFormat::Wkt ) );
36 mFormatComboBox->addItem( tr( "Proj String (Legacy — Not Recommended)" ), static_cast< int >( Qgis::CrsDefinitionFormat::Proj ) );
37 mFormatComboBox->setCurrentIndex( mFormatComboBox->findData( static_cast< int >( Qgis::CrsDefinitionFormat::Wkt ) ) );
38
39 connect( mFormatComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsCrsDefinitionWidget::formatChanged );
40 connect( mTextEditParameters, &QPlainTextEdit::textChanged, this, &QgsCrsDefinitionWidget::crsChanged );
41}
42
44{
46 switch ( static_cast< Qgis::CrsDefinitionFormat >( mFormatComboBox->currentData().toInt() ) )
47 {
49 crs = QgsCoordinateReferenceSystem::fromWkt( mTextEditParameters->toPlainText() );
50 break;
51
53 crs = QgsCoordinateReferenceSystem::fromProj( mTextEditParameters->toPlainText() );
54 break;
55 }
56
58 return crs;
59}
60
65
67{
68 switch ( nativeFormat )
69 {
71 whileBlocking( mTextEditParameters )->setPlainText( crs.toWkt( Qgis::CrsWktVariant::Preferred, false ) );
72 break;
74 whileBlocking( mTextEditParameters )->setPlainText( crs.toProj() );
75 break;
76 }
77
78 whileBlocking( mFormatComboBox )->setCurrentIndex( mFormatComboBox->findData( static_cast< int >( nativeFormat ) ) );
79 emit crsChanged();
80}
81
83{
84 return static_cast< Qgis::CrsDefinitionFormat >( mFormatComboBox->currentData().toInt() );
85}
86
88{
89 mFormatComboBox->setCurrentIndex( mFormatComboBox->findData( static_cast< int >( format ) ) );
90}
91
93{
94 return mTextEditParameters->toPlainText();
95}
96
97void QgsCrsDefinitionWidget::setDefinitionString( const QString &definition )
98{
99 mTextEditParameters->setPlainText( definition );
100}
101
102void QgsCrsDefinitionWidget::pbnCopyCRS_clicked()
103{
104 std::unique_ptr< QgsProjectionSelectionDialog > selector = std::make_unique< QgsProjectionSelectionDialog >( this );
105 if ( selector->exec() )
106 {
107 const QgsCoordinateReferenceSystem srs = selector->crs();
108
109 whileBlocking( mFormatComboBox )->setCurrentIndex( mFormatComboBox->findData( static_cast< int >( Qgis::CrsDefinitionFormat::Wkt ) ) );
110 mTextEditParameters->setPlainText( srs.toWkt( Qgis::CrsWktVariant::Preferred, true ) );
111 }
112}
113
114void QgsCrsDefinitionWidget::validateCurrent()
115{
116 const QString projDef = mTextEditParameters->toPlainText();
117
118 PJ_CONTEXT *context = QgsProjContext::get();
119
122
123 switch ( static_cast< Qgis::CrsDefinitionFormat >( mFormatComboBox->currentData().toInt() ) )
124 {
126 {
127 PROJ_STRING_LIST warnings = nullptr;
128 PROJ_STRING_LIST grammarErrors = nullptr;
129 crs.reset( proj_create_from_wkt( context, projDef.toUtf8().constData(), nullptr, &warnings, &grammarErrors ) );
130 QStringList warningStrings;
131 QStringList grammarStrings;
132 for ( auto iter = warnings; iter && *iter; ++iter )
133 warningStrings << QString( *iter );
134 for ( auto iter = grammarErrors; iter && *iter; ++iter )
135 grammarStrings << QString( *iter );
136 proj_string_list_destroy( warnings );
137 proj_string_list_destroy( grammarErrors );
138
139 if ( crs )
140 {
141 QMessageBox::information( this, tr( "Custom Coordinate Reference System" ),
142 tr( "This WKT projection definition is valid." ) );
143 }
144 else
145 {
146 QMessageBox::warning( this, tr( "Custom Coordinate Reference System" ),
147 tr( "This WKT projection definition is not valid:" ) + QStringLiteral( "\n\n" ) + warningStrings.join( '\n' ) + grammarStrings.join( '\n' ) );
148 }
149 break;
150 }
151
153 {
154 const QString projCrsString = projDef + ( projDef.contains( QStringLiteral( "+type=crs" ) ) ? QString() : QStringLiteral( " +type=crs" ) );
155 crs.reset( proj_create( context, projCrsString.toUtf8().constData() ) );
156 if ( crs )
157 {
158 QMessageBox::information( this, tr( "Custom Coordinate Reference System" ),
159 tr( "This proj projection definition is valid." ) );
160 }
161 else
162 {
163 QMessageBox::warning( this, tr( "Custom Coordinate Reference System" ),
164 tr( "This proj projection definition is not valid:" ) + QStringLiteral( "\n\n" ) + projLogger.errors().join( '\n' ) );
165 }
166 break;
167 }
168 }
169}
170
171void QgsCrsDefinitionWidget::formatChanged()
172{
174 QString newFormatString;
175 switch ( static_cast< Qgis::CrsDefinitionFormat >( mFormatComboBox->currentData().toInt() ) )
176 {
178 {
179 crs.createFromWkt( multiLineWktToSingleLine( mTextEditParameters->toPlainText() ) );
180 if ( crs.isValid() )
181 newFormatString = crs.toProj();
182 break;
183 }
184
186 {
187 PJ_CONTEXT *pjContext = QgsProjContext::get();
188 QString proj = mTextEditParameters->toPlainText();
189 proj.replace( QLatin1String( "+type=crs" ), QString() );
190 proj += QLatin1String( " +type=crs" );
191 QgsProjUtils::proj_pj_unique_ptr crs( proj_create( QgsProjContext::get(), proj.toUtf8().constData() ) );
192 if ( crs )
193 {
194 const QByteArray multiLineOption = QStringLiteral( "MULTILINE=YES" ).toLocal8Bit();
195 const char *const options[] = {multiLineOption.constData(), nullptr};
196 newFormatString = QString( proj_as_wkt( pjContext, crs.get(), PJ_WKT2_2019, options ) );
197 }
198 break;
199 }
200 }
201 if ( !newFormatString.isEmpty() )
202 mTextEditParameters->setPlainText( newFormatString );
203}
204
205void QgsCrsDefinitionWidget::pbnCalculate_clicked()
206{
207 // We must check the prj def is valid!
208 QString projDef = mTextEditParameters->toPlainText();
209
210 // Get the WGS84 coordinates
211 bool okN, okE;
212 double latitude = mNorthWGS84Edit->text().toDouble( &okN );
213 double longitude = mEastWGS84Edit->text().toDouble( &okE );
214
215 if ( !okN || !okE )
216 {
217 QMessageBox::warning( this, tr( "Custom Coordinate Reference System" ),
218 tr( "Latitude and Longitude must be in decimal form." ) );
219 mProjectedXLabel->clear();
220 mProjectedYLabel->clear();
221 return;
222 }
223
225 if ( static_cast< Qgis::CrsDefinitionFormat >( mFormatComboBox->currentData().toInt() ) == Qgis::CrsDefinitionFormat::Proj )
226 {
227 projDef = projDef + ( projDef.contains( QStringLiteral( "+type=crs" ) ) ? QString() : QStringLiteral( " +type=crs" ) );
228 target = QgsCoordinateReferenceSystem::fromProj( projDef );
229 }
230 else
231 {
232 target = QgsCoordinateReferenceSystem::fromWkt( projDef );
233 }
234
235 if ( !target.isValid() )
236 {
237 QMessageBox::warning( this, tr( "Custom Coordinate Reference System" ),
238 tr( "This CRS projection definition is not valid." ) );
239 mProjectedXLabel->clear();
240 mProjectedYLabel->clear();
241 return;
242 }
243
245 try
246 {
247 if ( target.celestialBodyName() == QLatin1String( "Earth" ) )
248 {
249 source = QgsCoordinateReferenceSystem( "EPSG:4326" );
250 }
251 else
252 {
253 source = target.toGeographicCrs();
254 }
255 }
256 catch ( QgsNotSupportedException & )
257 {
258 source = target.toGeographicCrs();
259 }
260
261 const QgsCoordinateTransform transform( source, target, QgsCoordinateTransformContext() );
262 try
263 {
264 const QgsPointXY res = transform.transform( QgsPointXY( longitude, latitude ) );
265 const int precision = target.isGeographic() ? 7 : 4;
266 mProjectedXLabel->setText( QLocale().toString( res.x(), 'f', precision ) );
267 mProjectedYLabel->setText( QLocale().toString( res.y(), 'f', precision ) );
268 }
269 catch ( QgsCsException &e )
270 {
271 mProjectedXLabel->setText( tr( "Error" ) );
272 mProjectedYLabel->setText( tr( "Error" ) );
273 QMessageBox::warning( this, tr( "Custom Coordinate Reference System" ),
274 e.what() );
275 }
276}
277
278QString QgsCrsDefinitionWidget::multiLineWktToSingleLine( const QString &wkt )
279{
280 QString res = wkt;
281 const thread_local QRegularExpression re( QStringLiteral( "\\s*\\n\\s*" ), QRegularExpression::MultilineOption );
282 res.replace( re, QString() );
283 return res;
284}
CrsDefinitionFormat
CRS definition formats.
Definition qgis.h:3613
@ Wkt
WKT format (always recommended over proj string format)
@ Proj
Proj string format.
@ Preferred
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromWkt(const QString &wkt)
Sets this CRS using a WKT definition.
QString toProj() const
Returns a Proj string representation of this CRS.
Qgis::CrsDefinitionFormat nativeFormat() const
Returns the native format for the CRS definition.
void setNativeFormat(Qgis::CrsDefinitionFormat format)
Sets the native format for the CRS definition.
QgsCoordinateReferenceSystem toGeographicCrs() const
Returns the geographic CRS associated with this CRS object.
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
QString celestialBodyName() const
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
void setDefinitionString(const QString &definition)
Sets the current definition string.
QString definitionString() const
Returns the current definition string.
void setFormat(Qgis::CrsDefinitionFormat format)
Sets the CRS format.
void crsChanged()
Emitted when the CRS defined in the widget is changed.
QgsCrsDefinitionWidget(QWidget *parent=nullptr)
Constructor for QgsCrsDefinitionWidget, with the specified parent widget.
Qgis::CrsDefinitionFormat format() const
Returns the selected CRS format.
QgsCoordinateReferenceSystem crs() const
Returns the current CRS as defined in the widget.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the current crs to display in the widget.
Custom exception class for Coordinate Reference System related exceptions.
QString what() const
Custom exception class which is raised when an operation is not supported.
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
std::unique_ptr< PJ, ProjPJDeleter > proj_pj_unique_ptr
Scoped Proj PJ object.
Scoped object for temporary swapping to an error-collecting PROJ log function.
QStringList errors() const
Returns the (possibly empty) list of collected errors.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5862
struct projCtx_t PJ_CONTEXT
const QgsCoordinateReferenceSystem & crs
int precision