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