QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgscoordinateutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscoordinateutils.cpp
3  ----------------------
4  begin : February 2016
5  copyright : (C) 2016 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 
18 #include "qgscoordinateutils.h"
20 #include "qgscoordinatetransform.h"
21 #include "qgsproject.h"
22 #include "qgis.h"
23 #include "qgsexception.h"
24 #include "qgscoordinateformatter.h"
26 
27 int QgsCoordinateUtils::calculateCoordinatePrecision( double mapUnitsPerPixel, const QgsCoordinateReferenceSystem &mapCrs, QgsProject *project )
28 {
29  if ( !project )
30  project = QgsProject::instance();
31  // Get the display precision from the project settings
32  bool automatic = project->readBoolEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ) );
33  int dp = 0;
34 
35  if ( automatic )
36  {
37  QString format = project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QStringLiteral( "MU" ) );
38  bool formatGeographic = ( format == QLatin1String( "DM" ) || format == QLatin1String( "DMS" ) || format == QLatin1String( "D" ) );
39 
40  // we can only calculate an automatic precision if one of these is true:
41  // - both map CRS and format are geographic
42  // - both map CRS and format are not geographic
43  // - map CRS is geographic but format is not geographic (i.e. map units)
44  if ( mapCrs.isGeographic() || !formatGeographic )
45  {
46  // Work out a suitable number of decimal places for the coordinates with the aim of always
47  // having enough decimal places to show the difference in position between adjacent pixels.
48  // Also avoid taking the log of 0.
49  if ( !qgsDoubleNear( mapUnitsPerPixel, 0.0 ) )
50  dp = static_cast<int>( std::ceil( -1.0 * std::log10( mapUnitsPerPixel ) ) );
51  }
52  else
53  {
54  if ( format == QLatin1String( "D" ) )
55  dp = 4;
56  else
57  dp = 2;
58  }
59  }
60  else
61  dp = project->readNumEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ) );
62 
63  // Keep dp sensible
64  if ( dp < 0 )
65  dp = 0;
66 
67  return dp;
68 }
69 
70 QString QgsCoordinateUtils::formatCoordinateForProject( QgsProject *project, const QgsPointXY &point, const QgsCoordinateReferenceSystem &destCrs, int precision )
71 {
72  if ( !project )
73  return QString();
74 
75  QString format = project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QStringLiteral( "MU" ) );
76 
77  QgsPointXY geo = point;
78  if ( format == QLatin1String( "DM" ) || format == QLatin1String( "DMS" ) || format == QLatin1String( "D" ) )
79  {
80  // degrees
81  if ( destCrs.isValid() && !destCrs.isGeographic() )
82  {
83  // need to transform to geographic coordinates
85  try
86  {
87  geo = ct.transform( point );
88  }
89  catch ( QgsCsException & )
90  {
91  return QString();
92  }
93  }
94 
95  if ( format == QLatin1String( "DM" ) )
97  else if ( format == QLatin1String( "DMS" ) )
99  else
100  return QgsCoordinateFormatter::asPair( geo.x(), geo.y(), precision );
101  }
102  else
103  {
104  // coordinates in map units
105  return QgsCoordinateFormatter::asPair( point.x(), point.y(), precision );
106  }
107 }
108 
int precision
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
bool readBoolEntry(const QString &scope, const QString &key, bool def=false, bool *ok=nullptr) const
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:280
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:89
double x
Definition: qgspointxy.h:47
const long GEOSRID
Magic number for a geographic coord sys in POSTGIS SRID.
Definition: qgis.h:573
Pad minute and second values with leading zeros, eg &#39;05&#39; instead of &#39;5&#39;.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:442
This class represents a coordinate reference system (CRS).
Class for doing transforms between two map coordinate systems.
Include a direction suffix (eg &#39;N&#39;, &#39;E&#39;, &#39;S&#39; or &#39;W&#39;), otherwise a "-" prefix is used for west and sou...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
Degrees and decimal minutes, eg 30degrees 45.55&#39;.
static QString asPair(double x, double y, int precision=12)
Formats coordinates as an "\a x,\a y" pair, with optional decimal precision (number of decimal places...
static QString format(const QgsPointXY &point, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats a point according to the specified parameters.
Degrees, minutes and seconds, eg 30 degrees 45&#39;30".
bool isValid() const
Returns whether this CRS is correctly initialized and usable.