QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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
37#include "moc_qgscoordinateoperationwidget.cpp"
38
40 : QWidget( parent )
41{
42 setupUi( this );
43
44 mLabelSrcDescription->setTextInteractionFlags( Qt::TextBrowserInteraction );
45 mLabelSrcDescription->setOpenExternalLinks( true );
46 mInstallGridButton->hide();
47
48 connect( mInstallGridButton, &QPushButton::clicked, this, &QgsCoordinateOperationWidget::installGrid );
49 connect( mAllowFallbackCheckBox, &QCheckBox::toggled, this, [this] {
50 if ( !mBlockSignals )
51 emit operationChanged();
52 } );
53 mCoordinateOperationTableWidget->setColumnCount( 3 );
54
55 QStringList headers;
56 headers << tr( "Transformation" ) << tr( "Accuracy (meters)" ) << tr( "Area of Use" );
57 mCoordinateOperationTableWidget->setHorizontalHeaderLabels( headers );
58
59 mHideDeprecatedCheckBox->setVisible( false );
60 mShowSupersededCheckBox->setVisible( true );
61 mLabelDstDescription->hide();
62
63 connect( mHideDeprecatedCheckBox, &QCheckBox::stateChanged, this, [this] { loadAvailableOperations(); } );
64 connect( mShowSupersededCheckBox, &QCheckBox::toggled, this, &QgsCoordinateOperationWidget::showSupersededToggled );
65 connect( mCoordinateOperationTableWidget, &QTableWidget::currentItemChanged, this, &QgsCoordinateOperationWidget::tableCurrentItemChanged );
66 connect( mCoordinateOperationTableWidget, &QTableWidget::itemDoubleClicked, this, &QgsCoordinateOperationWidget::operationDoubleClicked );
67
68 mLabelSrcDescription->clear();
69 mLabelDstDescription->clear();
70}
71
73{
74 if ( canvas )
75 {
76 // show canvas extent in preview widget
77 QPolygonF mainCanvasPoly = canvas->mapSettings().visiblePolygon();
78 QgsGeometry g = QgsGeometry::fromQPolygonF( mainCanvasPoly );
79 // close polygon
80 mainCanvasPoly << mainCanvasPoly.at( 0 );
82 {
83 // reproject extent
86 g = g.densifyByCount( 5 );
87 try
88 {
89 g.transform( ct );
90 }
91 catch ( QgsCsException & )
92 {
93 }
94 }
95 mAreaCanvas->setCanvasRect( g.boundingBox() );
96 }
97}
98
100{
101 mMakeDefaultCheckBox->setVisible( show );
102}
103
105{
106 return mMakeDefaultCheckBox->isChecked();
107}
108
110{
111 return !mCoordinateOperationTableWidget->selectedItems().isEmpty();
112}
113
114QList<QgsCoordinateOperationWidget::OperationDetails> QgsCoordinateOperationWidget::availableOperations() const
115{
116 QList<QgsCoordinateOperationWidget::OperationDetails> res;
117 res.reserve( mDatumTransforms.size() );
118 for ( const QgsDatumTransform::TransformDetails &details : mDatumTransforms )
119 {
121 op.proj = details.proj;
122 op.sourceTransformId = -1;
124 op.isAvailable = details.isAvailable;
125 res << op;
126 }
127 return res;
128}
129
130void QgsCoordinateOperationWidget::loadAvailableOperations()
131{
132 mCoordinateOperationTableWidget->setRowCount( 0 );
133
134 int row = 0;
135 int preferredInitialRow = -1;
136
137 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
138 {
139 auto item = std::make_unique<QTableWidgetItem>();
140 item->setData( ProjRole, transform.proj );
141 item->setData( AvailableRole, transform.isAvailable );
142 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
143
144 QString name = transform.name;
145 if ( !transform.authority.isEmpty() && !transform.code.isEmpty() )
146 name += QStringLiteral( " %1 %2:%3" ).arg( QString( QChar( 0x2013 ) ), transform.authority, transform.code );
147 item->setText( name );
148
149 if ( row == 0 ) // highlight first (preferred) operation
150 {
151 QFont f = item->font();
152 f.setBold( true );
153 item->setFont( f );
154 item->setForeground( QBrush( QColor( 0, 120, 0 ) ) );
155 }
156
157 if ( !transform.isAvailable )
158 {
159 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
160 }
161
162 if ( preferredInitialRow < 0 && transform.isAvailable )
163 {
164 // try to select a "preferred" entry by default
165 preferredInitialRow = row;
166 }
167
168 QString missingMessage;
169 if ( !transform.isAvailable )
170 {
171 QStringList gridMessages;
172 QStringList missingGrids;
173 QStringList missingGridPackages;
174 QStringList missingGridUrls;
175
176 for ( const QgsDatumTransform::GridDetails &grid : transform.grids )
177 {
178 if ( !grid.isAvailable )
179 {
180 missingGrids << grid.shortName;
181 missingGridPackages << grid.packageName;
182 missingGridUrls << grid.url;
183 QString m = tr( "This transformation requires the grid file “%1”, which is not available for use on the system." ).arg( grid.shortName );
184 if ( !grid.url.isEmpty() )
185 {
186 if ( !grid.packageName.isEmpty() )
187 {
188 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 );
189 }
190 else
191 {
192 m += ' ' + tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( grid.url );
193 }
194 }
195 gridMessages << m;
196 }
197 }
198
199 item->setData( MissingGridsRole, missingGrids );
200 item->setData( MissingGridPackageNamesRole, missingGridPackages );
201 item->setData( MissingGridUrlsRole, missingGridUrls );
202
203 if ( gridMessages.count() > 1 )
204 {
205 for ( int k = 0; k < gridMessages.count(); ++k )
206 gridMessages[k] = QStringLiteral( "<li>%1</li>" ).arg( gridMessages.at( k ) );
207
208 missingMessage = QStringLiteral( "<ul>%1</ul" ).arg( gridMessages.join( QString() ) );
209 }
210 else if ( !gridMessages.empty() )
211 {
212 missingMessage = gridMessages.constFirst();
213 }
214 }
215
216 QStringList areasOfUse;
217 QStringList authorityCodes;
218
219 QStringList opText;
220 QString lastSingleOpScope;
221 QString lastSingleOpRemarks;
222 for ( const QgsDatumTransform::SingleOperationDetails &singleOpDetails : transform.operationDetails )
223 {
224 QString text;
225 if ( !singleOpDetails.scope.isEmpty() )
226 {
227 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Scope" ), formatScope( singleOpDetails.scope ) );
228 lastSingleOpScope = singleOpDetails.scope;
229 }
230 if ( !singleOpDetails.remarks.isEmpty() )
231 {
232 if ( !text.isEmpty() )
233 text += QLatin1String( "<br>" );
234 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Remarks" ), singleOpDetails.remarks );
235 lastSingleOpRemarks = singleOpDetails.remarks;
236 }
237 if ( !singleOpDetails.areaOfUse.isEmpty() )
238 {
239 if ( !areasOfUse.contains( singleOpDetails.areaOfUse ) )
240 areasOfUse << singleOpDetails.areaOfUse;
241 }
242 if ( !singleOpDetails.authority.isEmpty() && !singleOpDetails.code.isEmpty() )
243 {
244 const QString identifier = QStringLiteral( "%1:%2" ).arg( singleOpDetails.authority, singleOpDetails.code );
245 if ( !authorityCodes.contains( identifier ) )
246 authorityCodes << identifier;
247 }
248
249 if ( !text.isEmpty() )
250 {
251 opText.append( text );
252 }
253 }
254
255 QString text;
256 if ( !transform.scope.isEmpty() && transform.scope != lastSingleOpScope )
257 {
258 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Scope" ), transform.scope );
259 }
260 if ( !transform.remarks.isEmpty() && transform.remarks != lastSingleOpRemarks )
261 {
262 if ( !text.isEmpty() )
263 text += QLatin1String( "<br>" );
264 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Remarks" ), transform.remarks );
265 }
266 if ( !text.isEmpty() )
267 {
268 opText.append( text );
269 }
270
271 if ( opText.count() > 1 )
272 {
273 for ( int k = 0; k < opText.count(); ++k )
274 opText[k] = QStringLiteral( "<li>%1</li>" ).arg( opText.at( k ) );
275 }
276
277 if ( !transform.areaOfUse.isEmpty() && !areasOfUse.contains( transform.areaOfUse ) )
278 areasOfUse << transform.areaOfUse;
279 item->setData( BoundsRole, transform.bounds );
280
281 const QString id = !transform.authority.isEmpty() && !transform.code.isEmpty() ? QStringLiteral( "%1:%2" ).arg( transform.authority, transform.code ) : QString();
282 if ( !id.isEmpty() && !authorityCodes.contains( id ) )
283 authorityCodes << id;
284
285 const QColor disabled = palette().color( QPalette::Disabled, QPalette::Text );
286 const QColor active = palette().color( QPalette::Active, QPalette::Text );
287
288 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 ) );
289 const QString toolTipString = QStringLiteral( "<b>%1</b>" ).arg( transform.name )
290 + ( !opText.empty() ? ( opText.count() == 1 ? QStringLiteral( "<p>%1</p>" ).arg( opText.at( 0 ) ) : QStringLiteral( "<ul>%1</ul>" ).arg( opText.join( QString() ) ) ) : QString() )
291 + ( !areasOfUse.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Area of use" ), areasOfUse.join( QLatin1String( ", " ) ) ) : QString() )
292 + ( !authorityCodes.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Identifiers" ), authorityCodes.join( QLatin1String( ", " ) ) ) : QString() )
293 + ( !missingMessage.isEmpty() ? QStringLiteral( "<p><b style=\"color: red\">%1</b></p>" ).arg( missingMessage ) : QString() )
294 + QStringLiteral( "<p><code style=\"color: %1\">%2</code></p>" ).arg( codeColor.name(), transform.proj );
295
296 item->setToolTip( toolTipString );
297 mCoordinateOperationTableWidget->setRowCount( row + 1 );
298 mCoordinateOperationTableWidget->setItem( row, 0, item.release() );
299
300 item = std::make_unique<QTableWidgetItem>();
301 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
302 item->setText( transform.accuracy >= 0 ? QLocale().toString( transform.accuracy ) : tr( "Unknown" ) );
303 item->setToolTip( toolTipString );
304 if ( !transform.isAvailable )
305 {
306 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
307 }
308 mCoordinateOperationTableWidget->setItem( row, 1, item.release() );
309
310 // area of use column
311 item = std::make_unique<QTableWidgetItem>();
312 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
313 item->setText( areasOfUse.join( QLatin1String( ", " ) ) );
314 item->setToolTip( toolTipString );
315 if ( !transform.isAvailable )
316 {
317 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
318 }
319 mCoordinateOperationTableWidget->setItem( row, 2, item.release() );
320
321 row++;
322 }
323
324 if ( mCoordinateOperationTableWidget->currentRow() < 0 )
325 mCoordinateOperationTableWidget->selectRow( preferredInitialRow >= 0 ? preferredInitialRow : 0 );
326
327 mCoordinateOperationTableWidget->resizeColumnsToContents();
328
329 tableCurrentItemChanged( nullptr, nullptr );
330}
331
333{
334 QgsSettings settings;
335 settings.setValue( QStringLiteral( "Windows/DatumTransformDialog/hideDeprecated" ), mHideDeprecatedCheckBox->isChecked() );
336
337 for ( int i = 0; i < 2; i++ )
338 {
339 settings.setValue( QStringLiteral( "Windows/DatumTransformDialog/columnWidths/%1" ).arg( i ), mCoordinateOperationTableWidget->columnWidth( i ) );
340 }
341}
342
344{
345 OperationDetails preferred;
346
347 // for proj 6, return the first available transform -- they are sorted by preference by proj already
348 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
349 {
350 if ( transform.isAvailable )
351 {
352 preferred.proj = transform.proj;
353 preferred.isAvailable = transform.isAvailable;
354 break;
355 }
356 }
357 return preferred;
358}
359
360QString QgsCoordinateOperationWidget::formatScope( const QString &s )
361{
362 QString scope = s;
363
364 const thread_local QRegularExpression reGNSS( QStringLiteral( "\\bGNSS\\b" ) );
365 scope.replace( reGNSS, QObject::tr( "GNSS (Global Navigation Satellite System)" ) );
366
367 const thread_local QRegularExpression reCORS( QStringLiteral( "\\bCORS\\b" ) );
368 scope.replace( reCORS, QObject::tr( "CORS (Continually Operating Reference Station)" ) );
369
370 return scope;
371}
372
374{
375 int row = mCoordinateOperationTableWidget->currentRow();
377
378 if ( row >= 0 )
379 {
380 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
381 op.sourceTransformId = srcItem ? srcItem->data( TransformIdRole ).toInt() : -1;
382 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
383 op.destinationTransformId = destItem ? destItem->data( TransformIdRole ).toInt() : -1;
384 op.proj = srcItem ? srcItem->data( ProjRole ).toString() : QString();
385 op.isAvailable = srcItem ? srcItem->data( AvailableRole ).toBool() : true;
386 op.allowFallback = mAllowFallbackCheckBox->isChecked();
387 }
388 else
389 {
390 op.sourceTransformId = -1;
392 op.proj = QString();
393 }
394 return op;
395}
396
398{
399 int prevRow = mCoordinateOperationTableWidget->currentRow();
400 mBlockSignals++;
401 for ( int row = 0; row < mCoordinateOperationTableWidget->rowCount(); ++row )
402 {
403 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
404 if ( srcItem && srcItem->data( ProjRole ).toString() == operation.proj )
405 {
406 mCoordinateOperationTableWidget->selectRow( row );
407 break;
408 }
409 }
410
411 bool fallbackChanged = mAllowFallbackCheckBox->isChecked() != operation.allowFallback;
412 mAllowFallbackCheckBox->setChecked( operation.allowFallback );
413 mBlockSignals--;
414
415 if ( mCoordinateOperationTableWidget->currentRow() != prevRow || fallbackChanged )
416 emit operationChanged();
417}
418
420{
421 const QString op = context.calculateCoordinateOperation( mSourceCrs, mDestinationCrs );
422 if ( !op.isEmpty() )
423 {
424 OperationDetails deets;
425 deets.proj = op;
426 deets.allowFallback = context.allowFallbackTransform( mSourceCrs, mDestinationCrs );
427 setSelectedOperation( deets );
428 }
429 else
430 {
432 }
433}
434
436{
437 mAllowFallbackCheckBox->setVisible( visible );
438}
439
440bool QgsCoordinateOperationWidget::gridShiftTransformation( const QString &itemText ) const
441{
442 return !itemText.isEmpty() && !itemText.contains( QLatin1String( "towgs84" ), Qt::CaseInsensitive );
443}
444
445bool QgsCoordinateOperationWidget::testGridShiftFileAvailability( QTableWidgetItem *item ) const
446{
447 if ( !item )
448 {
449 return true;
450 }
451
452 QString itemText = item->text();
453 if ( itemText.isEmpty() )
454 {
455 return true;
456 }
457
458 char *projLib = getenv( "PROJ_LIB" );
459 if ( !projLib ) //no information about installation directory
460 {
461 return true;
462 }
463
464 QStringList itemEqualSplit = itemText.split( '=' );
465 QString filename;
466 for ( int i = 1; i < itemEqualSplit.size(); ++i )
467 {
468 if ( i > 1 )
469 {
470 filename.append( '=' );
471 }
472 filename.append( itemEqualSplit.at( i ) );
473 }
474
475 QDir projDir( projLib );
476 if ( projDir.exists() )
477 {
478 //look if filename in directory
479 QStringList fileList = projDir.entryList();
480 QStringList::const_iterator fileIt = fileList.constBegin();
481 for ( ; fileIt != fileList.constEnd(); ++fileIt )
482 {
483#if defined( Q_OS_WIN )
484 if ( fileIt->compare( filename, Qt::CaseInsensitive ) == 0 )
485#else
486 if ( fileIt->compare( filename ) == 0 )
487#endif //Q_OS_WIN
488 {
489 return true;
490 }
491 }
492 item->setToolTip( tr( "File '%1' not found in directory '%2'" ).arg( filename, projDir.absolutePath() ) );
493 return false; //not found in PROJ_LIB directory
494 }
495 return true;
496}
497
498void QgsCoordinateOperationWidget::tableCurrentItemChanged( QTableWidgetItem *, QTableWidgetItem * )
499{
500 int row = mCoordinateOperationTableWidget->currentRow();
501 if ( row < 0 )
502 {
503 mLabelSrcDescription->clear();
504 mLabelDstDescription->clear();
505 mAreaCanvas->hide();
506 mInstallGridButton->hide();
507 }
508 else
509 {
510 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
511 mLabelSrcDescription->setText( srcItem ? srcItem->toolTip() : QString() );
512 if ( srcItem )
513 {
514 // find area of intersection of operation, source and dest bounding boxes
515 // see https://github.com/OSGeo/PROJ/issues/1549 for justification
516 const QgsRectangle operationRect = srcItem->data( BoundsRole ).value<QgsRectangle>();
517 const QgsRectangle sourceRect = mSourceCrs.bounds();
518 const QgsRectangle destRect = mDestinationCrs.bounds();
519 QgsRectangle rect = operationRect.intersect( sourceRect );
520 rect = rect.intersect( destRect );
521
522 mAreaCanvas->setPreviewRect( rect );
523 mAreaCanvas->show();
524
525 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
526 mInstallGridButton->setVisible( !missingGrids.empty() );
527 if ( !missingGrids.empty() )
528 {
529 mInstallGridButton->setText( tr( "Install “%1” Grid…" ).arg( missingGrids.at( 0 ) ) );
530 }
531 }
532 else
533 {
534 mAreaCanvas->setPreviewRect( QgsRectangle() );
535 mAreaCanvas->hide();
536 mInstallGridButton->hide();
537 }
538 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
539 mLabelDstDescription->setText( destItem ? destItem->toolTip() : QString() );
540 }
542 if ( newOp.proj != mPreviousOp.proj && !mBlockSignals )
543 emit operationChanged();
544 mPreviousOp = newOp;
545}
546
548{
549 mSourceCrs = sourceCrs;
550 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
551 loadAvailableOperations();
552}
553
555{
556 mDestinationCrs = destinationCrs;
557 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
558 loadAvailableOperations();
559}
560
561void QgsCoordinateOperationWidget::showSupersededToggled( bool )
562{
563 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
564 loadAvailableOperations();
565}
566
567void QgsCoordinateOperationWidget::installGrid()
568{
569 int row = mCoordinateOperationTableWidget->currentRow();
570 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
571 if ( !srcItem )
572 return;
573
574 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
575 if ( missingGrids.empty() )
576 return;
577
578 const QStringList missingGridPackagesNames = srcItem->data( MissingGridPackageNamesRole ).toStringList();
579 const QString packageName = missingGridPackagesNames.value( 0 );
580 const QStringList missingGridUrls = srcItem->data( MissingGridUrlsRole ).toStringList();
581 const QString gridUrl = missingGridUrls.value( 0 );
582
583 QString downloadMessage;
584 if ( !packageName.isEmpty() )
585 {
586 downloadMessage = tr( "This grid is part of the “<i>%1</i>” package, available for download from <a href=\"%2\">%2</a>." ).arg( packageName, gridUrl );
587 }
588 else if ( !gridUrl.isEmpty() )
589 {
590 downloadMessage = tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( gridUrl );
591 }
592
593 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 ) );
594
595 QgsInstallGridShiftFileDialog *dlg = new QgsInstallGridShiftFileDialog( missingGrids.at( 0 ), this );
596 dlg->setAttribute( Qt::WA_DeleteOnClose );
597 dlg->setWindowTitle( tr( "Install Grid File" ) );
598 dlg->setDescription( longMessage );
599 dlg->setDownloadMessage( downloadMessage );
600 dlg->exec();
601}
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:65
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.