QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
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
21#include "qgslogger.h"
22#include "qgssettings.h"
23#include "qgsproject.h"
24#include "qgsguiutils.h"
25#include "qgsgui.h"
26#include "qgshelp.h"
28
29#include <QDir>
30#include <QPushButton>
31#include <QRegularExpression>
32
33#include "qgsprojutils.h"
34#include <proj.h>
35
37 : QWidget( parent )
38{
39 setupUi( this );
40
41 mLabelSrcDescription->setTextInteractionFlags( Qt::TextBrowserInteraction );
42 mLabelSrcDescription->setOpenExternalLinks( true );
43 mInstallGridButton->hide();
44
45 connect( mInstallGridButton, &QPushButton::clicked, this, &QgsCoordinateOperationWidget::installGrid );
46 connect( mAllowFallbackCheckBox, &QCheckBox::toggled, this, [ = ]
47 {
48 if ( !mBlockSignals )
49 emit operationChanged();
50 } );
51 mCoordinateOperationTableWidget->setColumnCount( 3 );
52
53 QStringList headers;
54 headers << tr( "Transformation" ) << tr( "Accuracy (meters)" ) << tr( "Area of Use" );
55 mCoordinateOperationTableWidget->setHorizontalHeaderLabels( headers );
56
57 mHideDeprecatedCheckBox->setVisible( false );
58 mShowSupersededCheckBox->setVisible( true );
59 mLabelDstDescription->hide();
60
61 connect( mHideDeprecatedCheckBox, &QCheckBox::stateChanged, this, [ = ] { loadAvailableOperations(); } );
62 connect( mShowSupersededCheckBox, &QCheckBox::toggled, this, &QgsCoordinateOperationWidget::showSupersededToggled );
63 connect( mCoordinateOperationTableWidget, &QTableWidget::currentItemChanged, this, &QgsCoordinateOperationWidget::tableCurrentItemChanged );
64 connect( mCoordinateOperationTableWidget, &QTableWidget::itemDoubleClicked, this, &QgsCoordinateOperationWidget::operationDoubleClicked );
65
66 mLabelSrcDescription->clear();
67 mLabelDstDescription->clear();
68}
69
71{
72 if ( canvas )
73 {
74 // show canvas extent in preview widget
75 QPolygonF mainCanvasPoly = canvas->mapSettings().visiblePolygon();
76 QgsGeometry g = QgsGeometry::fromQPolygonF( mainCanvasPoly );
77 // close polygon
78 mainCanvasPoly << mainCanvasPoly.at( 0 );
79 if ( QgsProject::instance()->crs() !=
81 {
82 // 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 std::unique_ptr< QTableWidgetItem > 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 ),
289 static_cast< int >( active.green() * 0.6 + disabled.green() * 0.4 ),
290 static_cast< int >( active.blue() * 0.6 + disabled.blue() * 0.4 ) );
291 const QString toolTipString = QStringLiteral( "<b>%1</b>" ).arg( transform.name )
292 + ( !opText.empty() ? ( opText.count() == 1 ? QStringLiteral( "<p>%1</p>" ).arg( opText.at( 0 ) ) : QStringLiteral( "<ul>%1</ul>" ).arg( opText.join( QString() ) ) ) : QString() )
293 + ( !areasOfUse.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Area of use" ), areasOfUse.join( QLatin1String( ", " ) ) ) : QString() )
294 + ( !authorityCodes.empty() ? QStringLiteral( "<p><b>%1</b>: %2</p>" ).arg( tr( "Identifiers" ), authorityCodes.join( QLatin1String( ", " ) ) ) : QString() )
295 + ( !missingMessage.isEmpty() ? QStringLiteral( "<p><b style=\"color: red\">%1</b></p>" ).arg( missingMessage ) : QString() )
296 + QStringLiteral( "<p><code style=\"color: %1\">%2</code></p>" ).arg( codeColor.name(), transform.proj );
297
298 item->setToolTip( toolTipString );
299 mCoordinateOperationTableWidget->setRowCount( row + 1 );
300 mCoordinateOperationTableWidget->setItem( row, 0, item.release() );
301
302 item = std::make_unique< QTableWidgetItem >();
303 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
304 item->setText( transform.accuracy >= 0 ? QLocale().toString( transform.accuracy ) : tr( "Unknown" ) );
305 item->setToolTip( toolTipString );
306 if ( !transform.isAvailable )
307 {
308 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
309 }
310 mCoordinateOperationTableWidget->setItem( row, 1, item.release() );
311
312 // area of use column
313 item = std::make_unique< QTableWidgetItem >();
314 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
315 item->setText( areasOfUse.join( QLatin1String( ", " ) ) );
316 item->setToolTip( toolTipString );
317 if ( !transform.isAvailable )
318 {
319 item->setForeground( QBrush( palette().color( QPalette::Disabled, QPalette::Text ) ) );
320 }
321 mCoordinateOperationTableWidget->setItem( row, 2, item.release() );
322
323 row++;
324 }
325
326 if ( mCoordinateOperationTableWidget->currentRow() < 0 )
327 mCoordinateOperationTableWidget->selectRow( preferredInitialRow >= 0 ? preferredInitialRow : 0 );
328
329 mCoordinateOperationTableWidget->resizeColumnsToContents();
330
331 tableCurrentItemChanged( nullptr, nullptr );
332}
333
335{
336 QgsSettings settings;
337 settings.setValue( QStringLiteral( "Windows/DatumTransformDialog/hideDeprecated" ), mHideDeprecatedCheckBox->isChecked() );
338
339 for ( int i = 0; i < 2; i++ )
340 {
341 settings.setValue( QStringLiteral( "Windows/DatumTransformDialog/columnWidths/%1" ).arg( i ), mCoordinateOperationTableWidget->columnWidth( i ) );
342 }
343}
344
346{
347 OperationDetails preferred;
348
349 // for proj 6, return the first available transform -- they are sorted by preference by proj already
350 for ( const QgsDatumTransform::TransformDetails &transform : std::as_const( mDatumTransforms ) )
351 {
352 if ( transform.isAvailable )
353 {
354 preferred.proj = transform.proj;
355 preferred.isAvailable = transform.isAvailable;
356 break;
357 }
358 }
359 return preferred;
360}
361
362QString QgsCoordinateOperationWidget::formatScope( const QString &s )
363{
364 QString scope = s;
365
366 const thread_local QRegularExpression reGNSS( QStringLiteral( "\\bGNSS\\b" ) );
367 scope.replace( reGNSS, QObject::tr( "GNSS (Global Navigation Satellite System)" ) );
368
369 const thread_local QRegularExpression reCORS( QStringLiteral( "\\bCORS\\b" ) );
370 scope.replace( reCORS, QObject::tr( "CORS (Continually Operating Reference Station)" ) );
371
372 return scope;
373}
374
376{
377 int row = mCoordinateOperationTableWidget->currentRow();
379
380 if ( row >= 0 )
381 {
382 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
383 op.sourceTransformId = srcItem ? srcItem->data( TransformIdRole ).toInt() : -1;
384 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
385 op.destinationTransformId = destItem ? destItem->data( TransformIdRole ).toInt() : -1;
386 op.proj = srcItem ? srcItem->data( ProjRole ).toString() : QString();
387 op.isAvailable = srcItem ? srcItem->data( AvailableRole ).toBool() : true;
388 op.allowFallback = mAllowFallbackCheckBox->isChecked();
389 }
390 else
391 {
392 op.sourceTransformId = -1;
394 op.proj = QString();
395 }
396 return op;
397}
398
400{
401 int prevRow = mCoordinateOperationTableWidget->currentRow();
402 mBlockSignals++;
403 for ( int row = 0; row < mCoordinateOperationTableWidget->rowCount(); ++row )
404 {
405 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
406 if ( srcItem && srcItem->data( ProjRole ).toString() == operation.proj )
407 {
408 mCoordinateOperationTableWidget->selectRow( row );
409 break;
410 }
411 }
412
413 bool fallbackChanged = mAllowFallbackCheckBox->isChecked() != operation.allowFallback;
414 mAllowFallbackCheckBox->setChecked( operation.allowFallback );
415 mBlockSignals--;
416
417 if ( mCoordinateOperationTableWidget->currentRow() != prevRow || fallbackChanged )
418 emit operationChanged();
419}
420
422{
423 const QString op = context.calculateCoordinateOperation( mSourceCrs, mDestinationCrs );
424 if ( !op.isEmpty() )
425 {
426 OperationDetails deets;
427 deets.proj = op;
428 deets.allowFallback = context.allowFallbackTransform( mSourceCrs, mDestinationCrs );
429 setSelectedOperation( deets );
430 }
431 else
432 {
434 }
435}
436
438{
439 mAllowFallbackCheckBox->setVisible( visible );
440}
441
442bool QgsCoordinateOperationWidget::gridShiftTransformation( const QString &itemText ) const
443{
444 return !itemText.isEmpty() && !itemText.contains( QLatin1String( "towgs84" ), Qt::CaseInsensitive );
445}
446
447bool QgsCoordinateOperationWidget::testGridShiftFileAvailability( QTableWidgetItem *item ) const
448{
449 if ( !item )
450 {
451 return true;
452 }
453
454 QString itemText = item->text();
455 if ( itemText.isEmpty() )
456 {
457 return true;
458 }
459
460 char *projLib = getenv( "PROJ_LIB" );
461 if ( !projLib ) //no information about installation directory
462 {
463 return true;
464 }
465
466 QStringList itemEqualSplit = itemText.split( '=' );
467 QString filename;
468 for ( int i = 1; i < itemEqualSplit.size(); ++i )
469 {
470 if ( i > 1 )
471 {
472 filename.append( '=' );
473 }
474 filename.append( itemEqualSplit.at( i ) );
475 }
476
477 QDir projDir( projLib );
478 if ( projDir.exists() )
479 {
480 //look if filename in directory
481 QStringList fileList = projDir.entryList();
482 QStringList::const_iterator fileIt = fileList.constBegin();
483 for ( ; fileIt != fileList.constEnd(); ++fileIt )
484 {
485#if defined(Q_OS_WIN)
486 if ( fileIt->compare( filename, Qt::CaseInsensitive ) == 0 )
487#else
488 if ( fileIt->compare( filename ) == 0 )
489#endif //Q_OS_WIN
490 {
491 return true;
492 }
493 }
494 item->setToolTip( tr( "File '%1' not found in directory '%2'" ).arg( filename, projDir.absolutePath() ) );
495 return false; //not found in PROJ_LIB directory
496 }
497 return true;
498}
499
500void QgsCoordinateOperationWidget::tableCurrentItemChanged( QTableWidgetItem *, QTableWidgetItem * )
501{
502 int row = mCoordinateOperationTableWidget->currentRow();
503 if ( row < 0 )
504 {
505 mLabelSrcDescription->clear();
506 mLabelDstDescription->clear();
507 mAreaCanvas->hide();
508 mInstallGridButton->hide();
509 }
510 else
511 {
512 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
513 mLabelSrcDescription->setText( srcItem ? srcItem->toolTip() : QString() );
514 if ( srcItem )
515 {
516 // find area of intersection of operation, source and dest bounding boxes
517 // see https://github.com/OSGeo/PROJ/issues/1549 for justification
518 const QgsRectangle operationRect = srcItem->data( BoundsRole ).value< QgsRectangle >();
519 const QgsRectangle sourceRect = mSourceCrs.bounds();
520 const QgsRectangle destRect = mDestinationCrs.bounds();
521 QgsRectangle rect = operationRect.intersect( sourceRect );
522 rect = rect.intersect( destRect );
523
524 mAreaCanvas->setPreviewRect( rect );
525 mAreaCanvas->show();
526
527 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
528 mInstallGridButton->setVisible( !missingGrids.empty() );
529 if ( !missingGrids.empty() )
530 {
531 mInstallGridButton->setText( tr( "Install “%1” Grid…" ).arg( missingGrids.at( 0 ) ) );
532 }
533 }
534 else
535 {
536 mAreaCanvas->setPreviewRect( QgsRectangle() );
537 mAreaCanvas->hide();
538 mInstallGridButton->hide();
539 }
540 QTableWidgetItem *destItem = mCoordinateOperationTableWidget->item( row, 1 );
541 mLabelDstDescription->setText( destItem ? destItem->toolTip() : QString() );
542 }
543 OperationDetails newOp = selectedOperation();
544 if ( newOp.proj != mPreviousOp.proj && !mBlockSignals )
545 emit operationChanged();
546 mPreviousOp = newOp;
547}
548
550{
551 mSourceCrs = sourceCrs;
552 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
553 loadAvailableOperations();
554}
555
557{
558 mDestinationCrs = destinationCrs;
559 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
560 loadAvailableOperations();
561}
562
563void QgsCoordinateOperationWidget::showSupersededToggled( bool )
564{
565 mDatumTransforms = QgsDatumTransform::operations( mSourceCrs, mDestinationCrs, mShowSupersededCheckBox->isChecked() );
566 loadAvailableOperations();
567}
568
569void QgsCoordinateOperationWidget::installGrid()
570{
571 int row = mCoordinateOperationTableWidget->currentRow();
572 QTableWidgetItem *srcItem = mCoordinateOperationTableWidget->item( row, 0 );
573 if ( !srcItem )
574 return;
575
576 const QStringList missingGrids = srcItem->data( MissingGridsRole ).toStringList();
577 if ( missingGrids.empty() )
578 return;
579
580 const QStringList missingGridPackagesNames = srcItem->data( MissingGridPackageNamesRole ).toStringList();
581 const QString packageName = missingGridPackagesNames.value( 0 );
582 const QStringList missingGridUrls = srcItem->data( MissingGridUrlsRole ).toStringList();
583 const QString gridUrl = missingGridUrls.value( 0 );
584
585 QString downloadMessage;
586 if ( !packageName.isEmpty() )
587 {
588 downloadMessage = tr( "This grid is part of the “<i>%1</i>” package, available for download from <a href=\"%2\">%2</a>." ).arg( packageName, gridUrl );
589 }
590 else if ( !gridUrl.isEmpty() )
591 {
592 downloadMessage = tr( "This grid is available for download from <a href=\"%1\">%1</a>." ).arg( gridUrl );
593 }
594
595 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 ) );
596
597 QgsInstallGridShiftFileDialog *dlg = new QgsInstallGridShiftFileDialog( missingGrids.at( 0 ), this );
598 dlg->setAttribute( Qt::WA_DeleteOnClose );
599 dlg->setWindowTitle( tr( "Install Grid File" ) );
600 dlg->setDescription( longMessage );
601 dlg->setDownloadMessage( downloadMessage );
602 dlg->exec();
603}
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:63
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.