QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
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#include "moc_qgscoordinateoperationwidget.cpp"
22#include "qgslogger.h"
23#include "qgssettings.h"
24#include "qgsproject.h"
25#include "qgsguiutils.h"
26#include "qgsgui.h"
27#include "qgshelp.h"
29
30#include <QDir>
31#include <QPushButton>
32#include <QRegularExpression>
33
34#include "qgsprojutils.h"
35#include <proj.h>
36
38 : QWidget( parent )
39{
40 setupUi( this );
41
42 mLabelSrcDescription->setTextInteractionFlags( Qt::TextBrowserInteraction );
43 mLabelSrcDescription->setOpenExternalLinks( true );
44 mInstallGridButton->hide();
45
46 connect( mInstallGridButton, &QPushButton::clicked, this, &QgsCoordinateOperationWidget::installGrid );
47 connect( mAllowFallbackCheckBox, &QCheckBox::toggled, this, [ = ]
48 {
49 if ( !mBlockSignals )
50 emit operationChanged();
51 } );
52 mCoordinateOperationTableWidget->setColumnCount( 3 );
53
54 QStringList headers;
55 headers << tr( "Transformation" ) << tr( "Accuracy (meters)" ) << tr( "Area of Use" );
56 mCoordinateOperationTableWidget->setHorizontalHeaderLabels( headers );
57
58 mHideDeprecatedCheckBox->setVisible( false );
59 mShowSupersededCheckBox->setVisible( true );
60 mLabelDstDescription->hide();
61
62 connect( mHideDeprecatedCheckBox, &QCheckBox::stateChanged, this, [ = ] { loadAvailableOperations(); } );
63 connect( mShowSupersededCheckBox, &QCheckBox::toggled, this, &QgsCoordinateOperationWidget::showSupersededToggled );
64 connect( mCoordinateOperationTableWidget, &QTableWidget::currentItemChanged, this, &QgsCoordinateOperationWidget::tableCurrentItemChanged );
65 connect( mCoordinateOperationTableWidget, &QTableWidget::itemDoubleClicked, this, &QgsCoordinateOperationWidget::operationDoubleClicked );
66
67 mLabelSrcDescription->clear();
68 mLabelDstDescription->clear();
69}
70
72{
73 if ( canvas )
74 {
75 // show canvas extent in preview widget
76 QPolygonF mainCanvasPoly = canvas->mapSettings().visiblePolygon();
77 QgsGeometry g = QgsGeometry::fromQPolygonF( mainCanvasPoly );
78 // close polygon
79 mainCanvasPoly << mainCanvasPoly.at( 0 );
80 if ( QgsProject::instance()->crs() !=
82 {
83 // reproject extent
87 g = g.densifyByCount( 5 );
88 try
89 {
90 g.transform( ct );
91 }
92 catch ( QgsCsException & )
93 {
94 }
95 }
96 mAreaCanvas->setCanvasRect( g.boundingBox() );
97 }
98}
99
101{
102 mMakeDefaultCheckBox->setVisible( show );
103}
104
106{
107 return mMakeDefaultCheckBox->isChecked();
108}
109
111{
112 return !mCoordinateOperationTableWidget->selectedItems().isEmpty();
113}
114
115QList<QgsCoordinateOperationWidget::OperationDetails> QgsCoordinateOperationWidget::availableOperations() const
116{
117 QList<QgsCoordinateOperationWidget::OperationDetails> res;
118 res.reserve( mDatumTransforms.size() );
119 for ( const QgsDatumTransform::TransformDetails &details : mDatumTransforms )
120 {
122 op.proj = details.proj;
123 op.sourceTransformId = -1;
125 op.isAvailable = details.isAvailable;
126 res << op;
127 }
128 return res;
129}
130
131void QgsCoordinateOperationWidget::loadAvailableOperations()
132{
133 mCoordinateOperationTableWidget->setRowCount( 0 );
134
135 int row = 0;
136 int preferredInitialRow = -1;
137
138 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
139 {
140 std::unique_ptr< QTableWidgetItem > item = std::make_unique< QTableWidgetItem >();
141 item->setData( ProjRole, transform.proj );
142 item->setData( AvailableRole, transform.isAvailable );
143 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
144
145 QString name = transform.name;
146 if ( !transform.authority.isEmpty() && !transform.code.isEmpty() )
147 name += QStringLiteral( " %1 %2:%3" ).arg( QString( QChar( 0x2013 ) ), transform.authority, transform.code );
148 item->setText( name );
149
150 if ( row == 0 ) // highlight first (preferred) operation
151 {
152 QFont f = item->font();
153 f.setBold( true );
154 item->setFont( f );
155 item->setForeground( QBrush( QColor( 0, 120, 0 ) ) );
156 }
157
158 if ( !transform.isAvailable )
159 {
160 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
161 }
162
163 if ( preferredInitialRow < 0 && transform.isAvailable )
164 {
165 // try to select a "preferred" entry by default
166 preferredInitialRow = row;
167 }
168
169 QString missingMessage;
170 if ( !transform.isAvailable )
171 {
172 QStringList gridMessages;
173 QStringList missingGrids;
174 QStringList missingGridPackages;
175 QStringList missingGridUrls;
176
177 for ( const QgsDatumTransform::GridDetails &grid : transform.grids )
178 {
179 if ( !grid.isAvailable )
180 {
181 missingGrids << grid.shortName;
182 missingGridPackages << grid.packageName;
183 missingGridUrls << grid.url;
184 QString m = tr( "This transformation requires the grid file “%1”, which is not available for use on the system." ).arg( grid.shortName );
185 if ( !grid.url.isEmpty() )
186 {
187 if ( !grid.packageName.isEmpty() )
188 {
189 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 );
190 }
191 else
192 {
193 m += ' ' + tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( grid.url );
194 }
195 }
196 gridMessages << m;
197 }
198 }
199
200 item->setData( MissingGridsRole, missingGrids );
201 item->setData( MissingGridPackageNamesRole, missingGridPackages );
202 item->setData( MissingGridUrlsRole, missingGridUrls );
203
204 if ( gridMessages.count() > 1 )
205 {
206 for ( int k = 0; k < gridMessages.count(); ++k )
207 gridMessages[k] = QStringLiteral( "<li>%1</li>" ).arg( gridMessages.at( k ) );
208
209 missingMessage = QStringLiteral( "<ul>%1</ul" ).arg( gridMessages.join( QString() ) );
210 }
211 else if ( !gridMessages.empty() )
212 {
213 missingMessage = gridMessages.constFirst();
214 }
215 }
216
217 QStringList areasOfUse;
218 QStringList authorityCodes;
219
220 QStringList opText;
221 QString lastSingleOpScope;
222 QString lastSingleOpRemarks;
223 for ( const QgsDatumTransform::SingleOperationDetails &singleOpDetails : transform.operationDetails )
224 {
225 QString text;
226 if ( !singleOpDetails.scope.isEmpty() )
227 {
228 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Scope" ), formatScope( singleOpDetails.scope ) );
229 lastSingleOpScope = singleOpDetails.scope;
230 }
231 if ( !singleOpDetails.remarks.isEmpty() )
232 {
233 if ( !text.isEmpty() )
234 text += QLatin1String( "<br>" );
235 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Remarks" ), singleOpDetails.remarks );
236 lastSingleOpRemarks = singleOpDetails.remarks;
237 }
238 if ( !singleOpDetails.areaOfUse.isEmpty() )
239 {
240 if ( !areasOfUse.contains( singleOpDetails.areaOfUse ) )
241 areasOfUse << singleOpDetails.areaOfUse;
242 }
243 if ( !singleOpDetails.authority.isEmpty() && !singleOpDetails.code.isEmpty() )
244 {
245 const QString identifier = QStringLiteral( "%1:%2" ).arg( singleOpDetails.authority, singleOpDetails.code );
246 if ( !authorityCodes.contains( identifier ) )
247 authorityCodes << identifier;
248 }
249
250 if ( !text.isEmpty() )
251 {
252 opText.append( text );
253 }
254 }
255
256 QString text;
257 if ( !transform.scope.isEmpty() && transform.scope != lastSingleOpScope )
258 {
259 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Scope" ), transform.scope );
260 }
261 if ( !transform.remarks.isEmpty() && transform.remarks != lastSingleOpRemarks )
262 {
263 if ( !text.isEmpty() )
264 text += QLatin1String( "<br>" );
265 text += QStringLiteral( "<b>%1</b>: %2" ).arg( tr( "Remarks" ), transform.remarks );
266 }
267 if ( !text.isEmpty() )
268 {
269 opText.append( text );
270 }
271
272 if ( opText.count() > 1 )
273 {
274 for ( int k = 0; k < opText.count(); ++k )
275 opText[k] = QStringLiteral( "<li>%1</li>" ).arg( opText.at( k ) );
276 }
277
278 if ( !transform.areaOfUse.isEmpty() && !areasOfUse.contains( transform.areaOfUse ) )
279 areasOfUse << transform.areaOfUse;
280 item->setData( BoundsRole, transform.bounds );
281
282 const QString id = !transform.authority.isEmpty() && !transform.code.isEmpty() ? QStringLiteral( "%1:%2" ).arg( transform.authority, transform.code ) : QString();
283 if ( !id.isEmpty() && !authorityCodes.contains( id ) )
284 authorityCodes << id;
285
286 const QColor disabled = palette().color( QPalette::Disabled, QPalette::Text );
287 const QColor active = palette().color( QPalette::Active, QPalette::Text );
288
289 const QColor codeColor( static_cast< int >( active.red() * 0.6 + disabled.red() * 0.4 ),
290 static_cast< int >( active.green() * 0.6 + disabled.green() * 0.4 ),
291 static_cast< int >( active.blue() * 0.6 + disabled.blue() * 0.4 ) );
292 const QString toolTipString = QStringLiteral( "<b>%1</b>" ).arg( transform.name )
293 + ( !opText.empty() ? ( opText.count() == 1 ? QStringLiteral( "<p>%1</p>" ).arg( opText.at( 0 ) ) : QStringLiteral( "<ul>%1</ul>" ).arg( opText.join( QString() ) ) ) : QString() )
294 + ( !areasOfUse.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Area of use" ), areasOfUse.join( QLatin1String( ", " ) ) ) : QString() )
295 + ( !authorityCodes.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Identifiers" ), authorityCodes.join( QLatin1String( ", " ) ) ) : QString() )
296 + ( !missingMessage.isEmpty() ? QStringLiteral( "<p><b style=\"color: red\">%1</b></p>" ).arg( missingMessage ) : QString() )
297 + QStringLiteral( "<p><code style=\"color: %1\">%2</code></p>" ).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( QLatin1String( ", " ) ) );
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( QStringLiteral( "Windows/DatumTransformDialog/hideDeprecated" ), mHideDeprecatedCheckBox->isChecked() );
339
340 for ( int i = 0; i < 2; i++ )
341 {
342 settings.setValue( QStringLiteral( "Windows/DatumTransformDialog/columnWidths/%1" ).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( QStringLiteral( "\\bGNSS\\b" ) );
368 scope.replace( reGNSS, QObject::tr( "GNSS (Global Navigation Satellite System)" ) );
369
370 const thread_local QRegularExpression reCORS( QStringLiteral( "\\bCORS\\b" ) );
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( QLatin1String( "towgs84" ), 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 }
544 OperationDetails newOp = selectedOperation();
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.
This class represents a coordinate reference system (CRS).
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
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...
Class for doing transforms between two map 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.
A rectangle specified with double values.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
const QgsCoordinateReferenceSystem & crs
bool allowFallback
true if fallback transforms can be used
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.
Contains information about a projection transformation grid file.
Contains information about a single coordinate operation.
Contains information about a coordinate transformation operation.