QGIS API Documentation 4.1.0-Master (659fe69c07c)
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 if ( projectCrs.isEarthCrs() && projectCrs != QgsCoordinateReferenceSystem::fromEpsgId( 4326 ) )
86 {
87 // reproject extent
90 g = g.densifyByCount( 5 );
91 try
92 {
93 g.transform( ct );
94 }
95 catch ( QgsCsException & )
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
292 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 ) );
293 const QString toolTipString = u"<b>%1</b>"_s.arg( transform.name )
294 + ( !opText.empty() ? ( opText.count() == 1 ? u"<p>%1</p>"_s.arg( opText.at( 0 ) ) : u"<ul>%1</ul>"_s.arg( opText.join( QString() ) ) ) : QString() )
295 + ( !areasOfUse.empty() ? u"<p><b>%1</b>: %2</p>"_s.arg( tr( "Area of use" ), areasOfUse.join( ", "_L1 ) ) : QString() )
296 + ( !authorityCodes.empty() ? u"<p><b>%1</b>: %2</p>"_s.arg( tr( "Identifiers" ), authorityCodes.join( ", "_L1 ) ) : QString() )
297 + ( !missingMessage.isEmpty() ? u"<p><b style=\"color: red\">%1</b></p>"_s.arg( missingMessage ) : QString() )
298 + u"<p><code style=\"color: %1\">%2</code></p>"_s.arg( codeColor.name(), transform.proj );
299
300 item->setToolTip( toolTipString );
301 mCoordinateOperationTableWidget->setRowCount( row + 1 );
302 mCoordinateOperationTableWidget->setItem( row, 0, item.release() );
303
304 item = std::make_unique<QTableWidgetItem>();
305 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
306 item->setText( transform.accuracy >= 0 ? QLocale().toString( transform.accuracy ) : tr( "Unknown" ) );
307 item->setToolTip( toolTipString );
308 if ( !transform.isAvailable )
309 {
310 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
311 }
312 mCoordinateOperationTableWidget->setItem( row, 1, item.release() );
313
314 // area of use column
315 item = std::make_unique<QTableWidgetItem>();
316 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
317 item->setText( areasOfUse.join( ", "_L1 ) );
318 item->setToolTip( toolTipString );
319 if ( !transform.isAvailable )
320 {
321 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
322 }
323 mCoordinateOperationTableWidget->setItem( row, 2, item.release() );
324
325 row++;
326 }
327
328 if ( mCoordinateOperationTableWidget->currentRow() < 0 )
329 mCoordinateOperationTableWidget->selectRow( preferredInitialRow >= 0 ? preferredInitialRow : 0 );
330
331 mCoordinateOperationTableWidget->resizeColumnsToContents();
332
333 tableCurrentItemChanged( nullptr, nullptr );
334}
335
337{
338 QgsSettings settings;
339 settings.setValue( u"Windows/DatumTransformDialog/hideDeprecated"_s, mHideDeprecatedCheckBox->isChecked() );
340
341 for ( int i = 0; i < 2; i++ )
342 {
343 settings.setValue( u"Windows/DatumTransformDialog/columnWidths/%1"_s.arg( i ), mCoordinateOperationTableWidget->columnWidth( i ) );
344 }
345}
346
348{
349 OperationDetails preferred;
350
351 // for proj 6, return the first available transform -- they are sorted by preference by proj already
352 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
353 {
354 if ( transform.isAvailable )
355 {
356 preferred.proj = transform.proj;
357 preferred.isAvailable = transform.isAvailable;
358 break;
359 }
360 }
361 return preferred;
362}
363
364QString QgsCoordinateOperationWidget::formatScope( const QString &s )
365{
366 QString scope = s;
367
368 const thread_local QRegularExpression reGNSS( u"\\bGNSS\\b"_s );
369 scope.replace( reGNSS, QObject::tr( "GNSS (Global Navigation Satellite System)" ) );
370
371 const thread_local QRegularExpression reCORS( u"\\bCORS\\b"_s );
372 scope.replace( reCORS, QObject::tr( "CORS (Continually Operating Reference Station)" ) );
373
374 return scope;
375}
376
378{
379 int row = mCoordinateOperationTableWidget->currentRow();
381
382 if ( row >= 0 )
383 {
384 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
385 op.sourceTransformId = srcItem ? srcItem->data( TransformIdRole ).toInt() : -1;
386 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
387 op.destinationTransformId = destItem ? destItem->data( TransformIdRole ).toInt() : -1;
388 op.proj = srcItem ? srcItem->data( ProjRole ).toString() : QString();
389 op.isAvailable = srcItem ? srcItem->data( AvailableRole ).toBool() : true;
390 op.allowFallback = mAllowFallbackCheckBox->isChecked();
391 }
392 else
393 {
394 op.sourceTransformId = -1;
396 op.proj = QString();
397 }
398 return op;
399}
400
402{
403 int prevRow = mCoordinateOperationTableWidget->currentRow();
404 mBlockSignals++;
405 for ( int row = 0; row < mCoordinateOperationTableWidget->rowCount(); ++row )
406 {
407 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
408 if ( srcItem && srcItem->data( ProjRole ).toString() == operation.proj )
409 {
410 mCoordinateOperationTableWidget->selectRow( row );
411 break;
412 }
413 }
414
415 bool fallbackChanged = mAllowFallbackCheckBox->isChecked() != operation.allowFallback;
416 mAllowFallbackCheckBox->setChecked( operation.allowFallback );
417 mBlockSignals--;
418
419 if ( mCoordinateOperationTableWidget->currentRow() != prevRow || fallbackChanged )
420 emit operationChanged();
421}
422
424{
425 const QString op = context.calculateCoordinateOperation( mSourceCrs, mDestinationCrs );
426 if ( !op.isEmpty() )
427 {
428 OperationDetails deets;
429 deets.proj = op;
430 deets.allowFallback = context.allowFallbackTransform( mSourceCrs, mDestinationCrs );
431 setSelectedOperation( deets );
432 }
433 else
434 {
436 }
437}
438
440{
441 mAllowFallbackCheckBox->setVisible( visible );
442}
443
444bool QgsCoordinateOperationWidget::gridShiftTransformation( const QString &itemText ) const
445{
446 return !itemText.isEmpty() && !itemText.contains( "towgs84"_L1, Qt::CaseInsensitive );
447}
448
449bool QgsCoordinateOperationWidget::testGridShiftFileAvailability( QTableWidgetItem *item ) const
450{
451 if ( !item )
452 {
453 return true;
454 }
455
456 QString itemText = item->text();
457 if ( itemText.isEmpty() )
458 {
459 return true;
460 }
461
462 char *projLib = getenv( "PROJ_LIB" );
463 if ( !projLib ) //no information about installation directory
464 {
465 return true;
466 }
467
468 QStringList itemEqualSplit = itemText.split( '=' );
469 QString filename;
470 for ( int i = 1; i < itemEqualSplit.size(); ++i )
471 {
472 if ( i > 1 )
473 {
474 filename.append( '=' );
475 }
476 filename.append( itemEqualSplit.at( i ) );
477 }
478
479 QDir projDir( projLib );
480 if ( projDir.exists() )
481 {
482 //look if filename in directory
483 QStringList fileList = projDir.entryList();
484 QStringList::const_iterator fileIt = fileList.constBegin();
485 for ( ; fileIt != fileList.constEnd(); ++fileIt )
486 {
487#if defined( Q_OS_WIN )
488 if ( fileIt->compare( filename, Qt::CaseInsensitive ) == 0 )
489#else
490 if ( fileIt->compare( filename ) == 0 )
491#endif //Q_OS_WIN
492 {
493 return true;
494 }
495 }
496 item->setToolTip( tr( "File '%1' not found in directory '%2'" ).arg( filename, projDir.absolutePath() ) );
497 return false; //not found in PROJ_LIB directory
498 }
499 return true;
500}
501
502void QgsCoordinateOperationWidget::tableCurrentItemChanged( QTableWidgetItem *, QTableWidgetItem * )
503{
504 int row = mCoordinateOperationTableWidget->currentRow();
505 if ( row < 0 )
506 {
507 mLabelSrcDescription->clear();
508 mLabelDstDescription->clear();
509 mAreaCanvas->hide();
510 mInstallGridButton->hide();
511 }
512 else
513 {
514 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
515 mLabelSrcDescription->setText( srcItem ? srcItem->toolTip() : QString() );
516 if ( srcItem )
517 {
518 // find area of intersection of operation, source and dest bounding boxes
519 // see https://github.com/OSGeo/PROJ/issues/1549 for justification
520 const QgsRectangle operationRect = srcItem->data( BoundsRole ).value<QgsRectangle>();
521 const QgsRectangle sourceRect = mSourceCrs.bounds();
522 const QgsRectangle destRect = mDestinationCrs.bounds();
523 QgsRectangle rect = operationRect.intersect( sourceRect );
524 rect = rect.intersect( destRect );
525
526 mAreaCanvas->setPreviewRect( rect );
527 mAreaCanvas->show();
528
529 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
530 mInstallGridButton->setVisible( !missingGrids.empty() );
531 if ( !missingGrids.empty() )
532 {
533 mInstallGridButton->setText( tr( "Install “%1” Grid…" ).arg( missingGrids.at( 0 ) ) );
534 }
535 }
536 else
537 {
538 mAreaCanvas->setPreviewRect( QgsRectangle() );
539 mAreaCanvas->hide();
540 mInstallGridButton->hide();
541 }
542 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
543 mLabelDstDescription->setText( destItem ? destItem->toolTip() : QString() );
544 }
546 if ( newOp.proj != mPreviousOp.proj && !mBlockSignals )
547 emit operationChanged();
548 mPreviousOp = newOp;
549}
550
552{
553 mSourceCrs = sourceCrs;
554 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
555 loadAvailableOperations();
556}
557
559{
560 mDestinationCrs = destinationCrs;
561 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
562 loadAvailableOperations();
563}
564
565void QgsCoordinateOperationWidget::showSupersededToggled( bool )
566{
567 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
568 loadAvailableOperations();
569}
570
571void QgsCoordinateOperationWidget::installGrid()
572{
573 int row = mCoordinateOperationTableWidget->currentRow();
574 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
575 if ( !srcItem )
576 return;
577
578 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
579 if ( missingGrids.empty() )
580 return;
581
582 const QStringList missingGridPackagesNames = srcItem->data( MissingGridPackageNamesRole ).toStringList();
583 const QString packageName = missingGridPackagesNames.value( 0 );
584 const QStringList missingGridUrls = srcItem->data( MissingGridUrlsRole ).toStringList();
585 const QString gridUrl = missingGridUrls.value( 0 );
586
587 QString downloadMessage;
588 if ( !packageName.isEmpty() )
589 {
590 downloadMessage = tr( "This grid is part of the “<i>%1</i>” package, available for download from <a href=\"%2\">%2</a>." ).arg( packageName, gridUrl );
591 }
592 else if ( !gridUrl.isEmpty() )
593 {
594 downloadMessage = tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( gridUrl );
595 }
596
597 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 ) );
598
599 QgsInstallGridShiftFileDialog *dlg = new QgsInstallGridShiftFileDialog( missingGrids.at( 0 ), this );
600 dlg->setAttribute( Qt::WA_DeleteOnClose );
601 dlg->setWindowTitle( tr( "Install Grid File" ) );
602 dlg->setDescription( longMessage );
603 dlg->setDownloadMessage( downloadMessage );
604 dlg->exec();
605}
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.
bool isEarthCrs() const
Returns true if the CRS is associated with the Earth.
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.
QgsCoordinateReferenceSystem crs
Definition qgsproject.h:120
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.