QGIS API Documentation  3.2.0-Bonn (bc43194)
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 )
28 {
29  // Get the display precision from the project settings
30  bool automatic = QgsProject::instance()->readBoolEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ) );
31  int dp = 0;
32 
33  if ( automatic )
34  {
35  QString format = QgsProject::instance()->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QStringLiteral( "MU" ) );
36  bool formatGeographic = ( format == QLatin1String( "DM" ) || format == QLatin1String( "DMS" ) || format == QLatin1String( "D" ) );
37 
38  // we can only calculate an automatic precision if one of these is true:
39  // - both map CRS and format are geographic
40  // - both map CRS and format are not geographic
41  // - map CRS is geographic but format is not geographic (i.e. map units)
42  if ( mapCrs.isGeographic() || !formatGeographic )
43  {
44  // Work out a suitable number of decimal places for the coordinates with the aim of always
45  // having enough decimal places to show the difference in position between adjacent pixels.
46  // Also avoid taking the log of 0.
47  if ( !qgsDoubleNear( mapUnitsPerPixel, 0.0 ) )
48  dp = static_cast<int>( std::ceil( -1.0 * std::log10( mapUnitsPerPixel ) ) );
49  }
50  else
51  {
52  dp = format == QLatin1String( "D" ) ? 4 : 2; //guess sensible fallback
53  }
54  }
55  else
56  dp = QgsProject::instance()->readNumEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ) );
57 
58  // Keep dp sensible
59  if ( dp < 0 )
60  dp = 0;
61 
62  return dp;
63 }
64 
65 QString QgsCoordinateUtils::formatCoordinateForProject( QgsProject *project, const QgsPointXY &point, const QgsCoordinateReferenceSystem &destCrs, int precision )
66 {
67  if ( !project )
68  return QString();
69 
70  QString format = project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QStringLiteral( "MU" ) );
71 
72  QgsPointXY geo = point;
73  if ( format == QLatin1String( "DM" ) || format == QLatin1String( "DMS" ) || format == QLatin1String( "D" ) )
74  {
75  // degrees
76  if ( destCrs.isValid() && !destCrs.isGeographic() )
77  {
78  // need to transform to geographic coordinates
80  try
81  {
82  geo = ct.transform( point );
83  }
84  catch ( QgsCsException & )
85  {
86  return QString();
87  }
88  }
89 
90  if ( format == QLatin1String( "DM" ) )
92  else if ( format == QLatin1String( "DMS" ) )
94  else
95  return QgsCoordinateFormatter::asPair( geo.x(), geo.y(), precision );
96  }
97  else
98  {
99  // coordinates in map units
100  return QgsCoordinateFormatter::asPair( point.x(), point.y(), precision );
101  }
102 }
103 
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:251
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
Reads and writes project states.
Definition: qgsproject.h:85
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
double x
Definition: qgspointxy.h:47
const long GEOSRID
Magic number for a geographic coord sys in POSTGIS SRID.
Definition: qgis.h:462
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:391
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.