QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgscoordinateoperationwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscoordinateoperationwidget.cpp
3 ---------------------------
4 begin : December 2019
5 copyright : (C) 2019 by Nyall Dawson
6 email : nyall dot dawson at gmail dot 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
19
20#include <proj.h>
21
23#include "qgsgui.h"
24#include "qgsguiutils.h"
25#include "qgshelp.h"
27#include "qgslogger.h"
28#include "qgsproject.h"
30#include "qgsprojutils.h"
31#include "qgssettings.h"
32
33#include <QDir>
34#include <QPushButton>
35#include <QRegularExpression>
36#include <QString>
37
38#include "moc_qgscoordinateoperationwidget.cpp"
39
40using namespace Qt::StringLiterals;
41
43 : QWidget( parent )
44{
45 setupUi( this );
46
47 mLabelSrcDescription->setTextInteractionFlags( Qt::TextBrowserInteraction );
48 mLabelSrcDescription->setOpenExternalLinks( true );
49 mInstallGridButton->hide();
50
51 connect( mInstallGridButton, &QPushButton::clicked, this, &QgsCoordinateOperationWidget::installGrid );
52 connect( mAllowFallbackCheckBox, &QCheckBox::toggled, this, [this] {
53 if ( !mBlockSignals )
54 emit operationChanged();
55 } );
56 mCoordinateOperationTableWidget->setColumnCount( 3 );
57
58 QStringList headers;
59 headers << tr( "Transformation" ) << tr( "Accuracy (meters)" ) << tr( "Area of Use" );
60 mCoordinateOperationTableWidget->setHorizontalHeaderLabels( headers );
61
62 mHideDeprecatedCheckBox->setVisible( false );
63 mShowSupersededCheckBox->setVisible( true );
64 mLabelDstDescription->hide();
65
66 connect( mHideDeprecatedCheckBox, &QCheckBox::stateChanged, this, [this] { loadAvailableOperations(); } );
67 connect( mShowSupersededCheckBox, &QCheckBox::toggled, this, &QgsCoordinateOperationWidget::showSupersededToggled );
68 connect( mCoordinateOperationTableWidget, &QTableWidget::currentItemChanged, this, &QgsCoordinateOperationWidget::tableCurrentItemChanged );
69 connect( mCoordinateOperationTableWidget, &QTableWidget::itemDoubleClicked, this, &QgsCoordinateOperationWidget::operationDoubleClicked );
70
71 mLabelSrcDescription->clear();
72 mLabelDstDescription->clear();
73}
74
76{
77 if ( canvas )
78 {
79 // show canvas extent in preview widget
80 QPolygonF mainCanvasPoly = canvas->mapSettings().visiblePolygon();
81 QgsGeometry g = QgsGeometry::fromQPolygonF( mainCanvasPoly );
82 // close polygon
83 mainCanvasPoly << mainCanvasPoly.at( 0 );
85 {
86 // reproject extent
89 g = g.densifyByCount( 5 );
90 try
91 {
92 g.transform( ct );
93 }
94 catch ( QgsCsException & )
95 {
96 }
97 }
98 mAreaCanvas->setCanvasRect( g.boundingBox() );
99 }
100}
101
103{
104 mMakeDefaultCheckBox->setVisible( show );
105}
106
108{
109 return mMakeDefaultCheckBox->isChecked();
110}
111
113{
114 return !mCoordinateOperationTableWidget->selectedItems().isEmpty();
115}
116
117QList<QgsCoordinateOperationWidget::OperationDetails> QgsCoordinateOperationWidget::availableOperations() const
118{
119 QList<QgsCoordinateOperationWidget::OperationDetails> res;
120 res.reserve( mDatumTransforms.size() );
121 for ( const QgsDatumTransform::TransformDetails &details : mDatumTransforms )
122 {
124 op.proj = details.proj;
125 op.sourceTransformId = -1;
127 op.isAvailable = details.isAvailable;
128 res << op;
129 }
130 return res;
131}
132
133void QgsCoordinateOperationWidget::loadAvailableOperations()
134{
135 mCoordinateOperationTableWidget->setRowCount( 0 );
136
137 int row = 0;
138 int preferredInitialRow = -1;
139
140 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
141 {
142 auto item = std::make_unique<QTableWidgetItem>();
143 item->setData( ProjRole, transform.proj );
144 item->setData( AvailableRole, transform.isAvailable );
145 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
146
147 QString name = transform.name;
148 if ( !transform.authority.isEmpty() && !transform.code.isEmpty() )
149 name += u" %1 %2:%3"_s.arg( QString( QChar( 0x2013 ) ), transform.authority, transform.code );
150 item->setText( name );
151
152 if ( row == 0 ) // highlight first (preferred) operation
153 {
154 QFont f = item->font();
155 f.setBold( true );
156 item->setFont( f );
157 item->setForeground( QBrush( QColor( 0, 120, 0 ) ) );
158 }
159
160 if ( !transform.isAvailable )
161 {
162 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
163 }
164
165 if ( preferredInitialRow < 0 && transform.isAvailable )
166 {
167 // try to select a "preferred" entry by default
168 preferredInitialRow = row;
169 }
170
171 QString missingMessage;
172 if ( !transform.isAvailable )
173 {
174 QStringList gridMessages;
175 QStringList missingGrids;
176 QStringList missingGridPackages;
177 QStringList missingGridUrls;
178
179 for ( const QgsDatumTransform::GridDetails &grid : transform.grids )
180 {
181 if ( !grid.isAvailable )
182 {
183 missingGrids << grid.shortName;
184 missingGridPackages << grid.packageName;
185 missingGridUrls << grid.url;
186 QString m = tr( "This transformation requires the grid file “%1”, which is not available for use on the system." ).arg( grid.shortName );
187 if ( !grid.url.isEmpty() )
188 {
189 if ( !grid.packageName.isEmpty() )
190 {
191 m += ' ' + tr( "This grid is part of the <i>%1</i> package, available for download from <a href=\"%2\">%2</a>." ).arg( grid.packageName, grid.url );
192 }
193 else
194 {
195 m += ' ' + tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( grid.url );
196 }
197 }
198 gridMessages << m;
199 }
200 }
201
202 item->setData( MissingGridsRole, missingGrids );
203 item->setData( MissingGridPackageNamesRole, missingGridPackages );
204 item->setData( MissingGridUrlsRole, missingGridUrls );
205
206 if ( gridMessages.count() > 1 )
207 {
208 for ( int k = 0; k < gridMessages.count(); ++k )
209 gridMessages[k] = u"<li>%1</li>"_s.arg( gridMessages.at( k ) );
210
211 missingMessage = u"<ul>%1</ul"_s.arg( gridMessages.join( QString() ) );
212 }
213 else if ( !gridMessages.empty() )
214 {
215 missingMessage = gridMessages.constFirst();
216 }
217 }
218
219 QStringList areasOfUse;
220 QStringList authorityCodes;
221
222 QStringList opText;
223 QString lastSingleOpScope;
224 QString lastSingleOpRemarks;
225 for ( const QgsDatumTransform::SingleOperationDetails &singleOpDetails : transform.operationDetails )
226 {
227 QString text;
228 if ( !singleOpDetails.scope.isEmpty() )
229 {
230 text += u"<b>%1</b>: %2"_s.arg( tr( "Scope" ), formatScope( singleOpDetails.scope ) );
231 lastSingleOpScope = singleOpDetails.scope;
232 }
233 if ( !singleOpDetails.remarks.isEmpty() )
234 {
235 if ( !text.isEmpty() )
236 text += "<br>"_L1;
237 text += u"<b>%1</b>: %2"_s.arg( tr( "Remarks" ), singleOpDetails.remarks );
238 lastSingleOpRemarks = singleOpDetails.remarks;
239 }
240 if ( !singleOpDetails.areaOfUse.isEmpty() )
241 {
242 if ( !areasOfUse.contains( singleOpDetails.areaOfUse ) )
243 areasOfUse << singleOpDetails.areaOfUse;
244 }
245 if ( !singleOpDetails.authority.isEmpty() && !singleOpDetails.code.isEmpty() )
246 {
247 const QString identifier = u"%1:%2"_s.arg( singleOpDetails.authority, singleOpDetails.code );
248 if ( !authorityCodes.contains( identifier ) )
249 authorityCodes << identifier;
250 }
251
252 if ( !text.isEmpty() )
253 {
254 opText.append( text );
255 }
256 }
257
258 QString text;
259 if ( !transform.scope.isEmpty() && transform.scope != lastSingleOpScope )
260 {
261 text += u"<b>%1</b>: %2"_s.arg( tr( "Scope" ), transform.scope );
262 }
263 if ( !transform.remarks.isEmpty() && transform.remarks != lastSingleOpRemarks )
264 {
265 if ( !text.isEmpty() )
266 text += "<br>"_L1;
267 text += u"<b>%1</b>: %2"_s.arg( tr( "Remarks" ), transform.remarks );
268 }
269 if ( !text.isEmpty() )
270 {
271 opText.append( text );
272 }
273
274 if ( opText.count() > 1 )
275 {
276 for ( int k = 0; k < opText.count(); ++k )
277 opText[k] = u"<li>%1</li>"_s.arg( opText.at( k ) );
278 }
279
280 if ( !transform.areaOfUse.isEmpty() && !areasOfUse.contains( transform.areaOfUse ) )
281 areasOfUse << transform.areaOfUse;
282 item->setData( BoundsRole, transform.bounds );
283
284 const QString id = !transform.authority.isEmpty() && !transform.code.isEmpty() ? u"%1:%2"_s.arg( transform.authority, transform.code ) : QString();
285 if ( !id.isEmpty() && !authorityCodes.contains( id ) )
286 authorityCodes << id;
287
288 const QColor disabled = palette().color( QPalette::Disabled, QPalette::Text );
289 const QColor active = palette().color( QPalette::Active, QPalette::Text );
290
291 const QColor codeColor( static_cast<int>( active.red() * 0.6 + disabled.red() * 0.4 ), static_cast<int>( active.green() * 0.6 + disabled.green() * 0.4 ), static_cast<int>( active.blue() * 0.6 + disabled.blue() * 0.4 ) );
292 const QString toolTipString = u"<b>%1</b>"_s.arg( transform.name )
293 + ( !opText.empty() ? ( opText.count() == 1 ? u"<p>%1</p>"_s.arg( opText.at( 0 ) ) : u"<ul>%1</ul>"_s.arg( opText.join( QString() ) ) ) : QString() )
294 + ( !areasOfUse.empty() ? u"<p><b>%1</b>: %2</p>"_s.arg( tr( "Area of use" ), areasOfUse.join( ", "_L1 ) ) : QString() )
295 + ( !authorityCodes.empty() ? u"<p><b>%1</b>: %2</p>"_s.arg( tr( "Identifiers" ), authorityCodes.join( ", "_L1 ) ) : QString() )
296 + ( !missingMessage.isEmpty() ? u"<p><b style=\"color: red\">%1</b></p>"_s.arg( missingMessage ) : QString() )
297 + u"<p><code style=\"color: %1\">%2</code></p>"_s.arg( codeColor.name(), transform.proj );
298
299 item->setToolTip( toolTipString );
300 mCoordinateOperationTableWidget->setRowCount( row + 1 );
301 mCoordinateOperationTableWidget->setItem( row, 0, item.release() );
302
303 item = std::make_unique<QTableWidgetItem>();
304 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
305 item->setText( transform.accuracy >= 0 ? QLocale().toString( transform.accuracy ) : tr( "Unknown" ) );
306 item->setToolTip( toolTipString );
307 if ( !transform.isAvailable )
308 {
309 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
310 }
311 mCoordinateOperationTableWidget->setItem( row, 1, item.release() );
312
313 // area of use column
314 item = std::make_unique<QTableWidgetItem>();
315 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
316 item->setText( areasOfUse.join( ", "_L1 ) );
317 item->setToolTip( toolTipString );
318 if ( !transform.isAvailable )
319 {
320 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
321 }
322 mCoordinateOperationTableWidget->setItem( row, 2, item.release() );
323
324 row++;
325 }
326
327 if ( mCoordinateOperationTableWidget->currentRow() < 0 )
328 mCoordinateOperationTableWidget->selectRow( preferredInitialRow >= 0 ? preferredInitialRow : 0 );
329
330 mCoordinateOperationTableWidget->resizeColumnsToContents();
331
332 tableCurrentItemChanged( nullptr, nullptr );
333}
334
336{
337 QgsSettings settings;
338 settings.setValue( u"Windows/DatumTransformDialog/hideDeprecated"_s, mHideDeprecatedCheckBox->isChecked() );
339
340 for ( int i = 0; i < 2; i++ )
341 {
342 settings.setValue( u"Windows/DatumTransformDialog/columnWidths/%1"_s.arg( i ), mCoordinateOperationTableWidget->columnWidth( i ) );
343 }
344}
345
347{
348 OperationDetails preferred;
349
350 // for proj 6, return the first available transform -- they are sorted by preference by proj already
351 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
352 {
353 if ( transform.isAvailable )
354 {
355 preferred.proj = transform.proj;
356 preferred.isAvailable = transform.isAvailable;
357 break;
358 }
359 }
360 return preferred;
361}
362
363QString QgsCoordinateOperationWidget::formatScope( const QString &s )
364{
365 QString scope = s;
366
367 const thread_local QRegularExpression reGNSS( u"\\bGNSS\\b"_s );
368 scope.replace( reGNSS, QObject::tr( "GNSS (Global Navigation Satellite System)" ) );
369
370 const thread_local QRegularExpression reCORS( u"\\bCORS\\b"_s );
371 scope.replace( reCORS, QObject::tr( "CORS (Continually Operating Reference Station)" ) );
372
373 return scope;
374}
375
377{
378 int row = mCoordinateOperationTableWidget->currentRow();
380
381 if ( row >= 0 )
382 {
383 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
384 op.sourceTransformId = srcItem ? srcItem->data( TransformIdRole ).toInt() : -1;
385 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
386 op.destinationTransformId = destItem ? destItem->data( TransformIdRole ).toInt() : -1;
387 op.proj = srcItem ? srcItem->data( ProjRole ).toString() : QString();
388 op.isAvailable = srcItem ? srcItem->data( AvailableRole ).toBool() : true;
389 op.allowFallback = mAllowFallbackCheckBox->isChecked();
390 }
391 else
392 {
393 op.sourceTransformId = -1;
395 op.proj = QString();
396 }
397 return op;
398}
399
401{
402 int prevRow = mCoordinateOperationTableWidget->currentRow();
403 mBlockSignals++;
404 for ( int row = 0; row < mCoordinateOperationTableWidget->rowCount(); ++row )
405 {
406 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
407 if ( srcItem && srcItem->data( ProjRole ).toString() == operation.proj )
408 {
409 mCoordinateOperationTableWidget->selectRow( row );
410 break;
411 }
412 }
413
414 bool fallbackChanged = mAllowFallbackCheckBox->isChecked() != operation.allowFallback;
415 mAllowFallbackCheckBox->setChecked( operation.allowFallback );
416 mBlockSignals--;
417
418 if ( mCoordinateOperationTableWidget->currentRow() != prevRow || fallbackChanged )
419 emit operationChanged();
420}
421
423{
424 const QString op = context.calculateCoordinateOperation( mSourceCrs, mDestinationCrs );
425 if ( !op.isEmpty() )
426 {
427 OperationDetails deets;
428 deets.proj = op;
429 deets.allowFallback = context.allowFallbackTransform( mSourceCrs, mDestinationCrs );
430 setSelectedOperation( deets );
431 }
432 else
433 {
435 }
436}
437
439{
440 mAllowFallbackCheckBox->setVisible( visible );
441}
442
443bool QgsCoordinateOperationWidget::gridShiftTransformation( const QString &itemText ) const
444{
445 return !itemText.isEmpty() && !itemText.contains( "towgs84"_L1, Qt::CaseInsensitive );
446}
447
448bool QgsCoordinateOperationWidget::testGridShiftFileAvailability( QTableWidgetItem *item ) const
449{
450 if ( !item )
451 {
452 return true;
453 }
454
455 QString itemText = item->text();
456 if ( itemText.isEmpty() )
457 {
458 return true;
459 }
460
461 char *projLib = getenv( "PROJ_LIB" );
462 if ( !projLib ) //no information about installation directory
463 {
464 return true;
465 }
466
467 QStringList itemEqualSplit = itemText.split( '=' );
468 QString filename;
469 for ( int i = 1; i < itemEqualSplit.size(); ++i )
470 {
471 if ( i > 1 )
472 {
473 filename.append( '=' );
474 }
475 filename.append( itemEqualSplit.at( i ) );
476 }
477
478 QDir projDir( projLib );
479 if ( projDir.exists() )
480 {
481 //look if filename in directory
482 QStringList fileList = projDir.entryList();
483 QStringList::const_iterator fileIt = fileList.constBegin();
484 for ( ; fileIt != fileList.constEnd(); ++fileIt )
485 {
486#if defined( Q_OS_WIN )
487 if ( fileIt->compare( filename, Qt::CaseInsensitive ) == 0 )
488#else
489 if ( fileIt->compare( filename ) == 0 )
490#endif //Q_OS_WIN
491 {
492 return true;
493 }
494 }
495 item->setToolTip( tr( "File '%1' not found in directory '%2'" ).arg( filename, projDir.absolutePath() ) );
496 return false; //not found in PROJ_LIB directory
497 }
498 return true;
499}
500
501void QgsCoordinateOperationWidget::tableCurrentItemChanged( QTableWidgetItem *, QTableWidgetItem * )
502{
503 int row = mCoordinateOperationTableWidget->currentRow();
504 if ( row < 0 )
505 {
506 mLabelSrcDescription->clear();
507 mLabelDstDescription->clear();
508 mAreaCanvas->hide();
509 mInstallGridButton->hide();
510 }
511 else
512 {
513 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
514 mLabelSrcDescription->setText( srcItem ? srcItem->toolTip() : QString() );
515 if ( srcItem )
516 {
517 // find area of intersection of operation, source and dest bounding boxes
518 // see https://github.com/OSGeo/PROJ/issues/1549 for justification
519 const QgsRectangle operationRect = srcItem->data( BoundsRole ).value<QgsRectangle>();
520 const QgsRectangle sourceRect = mSourceCrs.bounds();
521 const QgsRectangle destRect = mDestinationCrs.bounds();
522 QgsRectangle rect = operationRect.intersect( sourceRect );
523 rect = rect.intersect( destRect );
524
525 mAreaCanvas->setPreviewRect( rect );
526 mAreaCanvas->show();
527
528 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
529 mInstallGridButton->setVisible( !missingGrids.empty() );
530 if ( !missingGrids.empty() )
531 {
532 mInstallGridButton->setText( tr( "Install “%1” Grid…" ).arg( missingGrids.at( 0 ) ) );
533 }
534 }
535 else
536 {
537 mAreaCanvas->setPreviewRect( QgsRectangle() );
538 mAreaCanvas->hide();
539 mInstallGridButton->hide();
540 }
541 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
542 mLabelDstDescription->setText( destItem ? destItem->toolTip() : QString() );
543 }
545 if ( newOp.proj != mPreviousOp.proj && !mBlockSignals )
546 emit operationChanged();
547 mPreviousOp = newOp;
548}
549
551{
552 mSourceCrs = sourceCrs;
553 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
554 loadAvailableOperations();
555}
556
558{
559 mDestinationCrs = destinationCrs;
560 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
561 loadAvailableOperations();
562}
563
564void QgsCoordinateOperationWidget::showSupersededToggled( bool )
565{
566 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
567 loadAvailableOperations();
568}
569
570void QgsCoordinateOperationWidget::installGrid()
571{
572 int row = mCoordinateOperationTableWidget->currentRow();
573 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
574 if ( !srcItem )
575 return;
576
577 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
578 if ( missingGrids.empty() )
579 return;
580
581 const QStringList missingGridPackagesNames = srcItem->data( MissingGridPackageNamesRole ).toStringList();
582 const QString packageName = missingGridPackagesNames.value( 0 );
583 const QStringList missingGridUrls = srcItem->data( MissingGridUrlsRole ).toStringList();
584 const QString gridUrl = missingGridUrls.value( 0 );
585
586 QString downloadMessage;
587 if ( !packageName.isEmpty() )
588 {
589 downloadMessage = tr( "This grid is part of the “<i>%1</i>” package, available for download from <a href=\"%2\">%2</a>." ).arg( packageName, gridUrl );
590 }
591 else if ( !gridUrl.isEmpty() )
592 {
593 downloadMessage = tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( gridUrl );
594 }
595
596 const QString longMessage = tr( "<p>This transformation requires the grid file “%1”, which is not available for use on the system.</p>" ).arg( missingGrids.at( 0 ) );
597
598 QgsInstallGridShiftFileDialog *dlg = new QgsInstallGridShiftFileDialog( missingGrids.at( 0 ), this );
599 dlg->setAttribute( Qt::WA_DeleteOnClose );
600 dlg->setWindowTitle( tr( "Install Grid File" ) );
601 dlg->setDescription( longMessage );
602 dlg->setDownloadMessage( downloadMessage );
603 dlg->exec();
604}
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination crs for the operations shown in the widget.
QgsCoordinateOperationWidget::OperationDetails selectedOperation() const
Returns the details of the operation currently selected within the widget.
bool makeDefaultSelected() const
Returns true if the "make default" option is selected.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS for the operations shown in the widget.
void setShowMakeDefault(bool show)
Sets whether the "make default" checkbox should be shown.
void operationChanged()
Emitted when the operation selected in the dialog is changed.
void operationDoubleClicked()
Emitted when an operation is double-clicked in the widget.
bool hasSelection() const
Returns true if there is a valid selection in the widget.
void setShowFallbackOption(bool visible)
Sets whether the "allow fallback" operations option is visible.
QgsCoordinateOperationWidget::OperationDetails defaultOperation() const
Returns the details of the default operation suggested by the widget.
QgsCoordinateOperationWidget(QWidget *parent=nullptr)
Constructor for QgsCoordinateOperationWidget.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to link to the widget, which allows the widget's choices to reflect the current can...
void setSelectedOperationUsingContext(const QgsCoordinateTransformContext &context)
Automatically sets the selected operation using the settings encapsulated in a transform context.
QList< QgsCoordinateOperationWidget::OperationDetails > availableOperations() const
Returns a list of the available operations shown in the widget.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source crs for the operations shown in the widget.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination CRS for the operations shown in the widget.
void setSelectedOperation(const QgsCoordinateOperationWidget::OperationDetails &operation)
Sets the details of the operation currently selected within the widget.
Represents a coordinate reference system (CRS).
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
Contains information about the context in which a coordinate transform is executed.
bool allowFallbackTransform(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns true if approximate "ballpark" transforms may be used when transforming between a source and ...
QString calculateCoordinateOperation(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns the Proj coordinate operation string to use when transforming from the specified source CRS t...
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Custom exception class for Coordinate Reference System related exceptions.
static QList< QgsDatumTransform::TransformDetails > operations(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination, bool includeSuperseded=false)
Returns a list of coordinate operations available for transforming coordinates from the source to des...
A geometry is the spatial representation of a feature.
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Map canvas is a class for displaying all GIS data types on a canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QPolygonF visiblePolygon() const
Returns the visible area as a polygon (may be rotated).
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Stores settings for use within QGIS.
Definition qgssettings.h:68
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
bool allowFallback
true if fallback transforms can be used
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.
QString shortName
Short name of transform grid.
bool isAvailable
true if grid is currently available for use
QString packageName
Name of package the grid is included within.
QString url
Url to download grid from.
QString authority
Authority name, e.g. EPSG.
QString code
Authority code, e.g. "8447" (for EPSG:8447).
QString remarks
Remarks for operation, from EPSG registry database.
QString areaOfUse
Area of use, from EPSG registry database.
QString scope
Scope of operation, from EPSG registry database.
Contains information about a coordinate transformation operation.