LCOV - code coverage report
Current view: top level - core - qgscoordinateutils.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 104 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       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"
      19                 :            : #include "qgscoordinatereferencesystem.h"
      20                 :            : #include "qgscoordinatetransform.h"
      21                 :            : #include "qgsproject.h"
      22                 :            : #include "qgis.h"
      23                 :            : #include "qgsexception.h"
      24                 :            : #include "qgscoordinateformatter.h"
      25                 :            : #include "qgsrectangle.h"
      26                 :            : #include <QRegularExpression>
      27                 :            : 
      28                 :            : ///@cond NOT_STABLE_API
      29                 :            : 
      30                 :          0 : int QgsCoordinateUtils::calculateCoordinatePrecision( double mapUnitsPerPixel, const QgsCoordinateReferenceSystem &mapCrs, QgsProject *project )
      31                 :            : {
      32                 :          0 :   if ( !project )
      33                 :          0 :     project = QgsProject::instance();
      34                 :            :   // Get the display precision from the project settings
      35                 :          0 :   bool automatic = project->readBoolEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ) );
      36                 :          0 :   int dp = 0;
      37                 :            : 
      38                 :          0 :   if ( automatic )
      39                 :            :   {
      40                 :          0 :     QString format = project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QStringLiteral( "MU" ) );
      41                 :          0 :     bool formatGeographic = ( format == QLatin1String( "DM" ) || format == QLatin1String( "DMS" ) || format == QLatin1String( "D" ) );
      42                 :            : 
      43                 :            :     // we can only calculate an automatic precision if one of these is true:
      44                 :            :     // - both map CRS and format are geographic
      45                 :            :     // - both map CRS and format are not geographic
      46                 :            :     // - map CRS is geographic but format is not geographic (i.e. map units)
      47                 :          0 :     if ( mapCrs.isGeographic() || !formatGeographic )
      48                 :            :     {
      49                 :            :       // Work out a suitable number of decimal places for the coordinates with the aim of always
      50                 :            :       // having enough decimal places to show the difference in position between adjacent pixels.
      51                 :            :       // Also avoid taking the log of 0.
      52                 :          0 :       if ( !qgsDoubleNear( mapUnitsPerPixel, 0.0 ) )
      53                 :          0 :         dp = static_cast<int>( std::ceil( -1.0 * std::log10( mapUnitsPerPixel ) ) );
      54                 :          0 :     }
      55                 :            :     else
      56                 :            :     {
      57                 :          0 :       if ( format == QLatin1String( "D" ) )
      58                 :          0 :         dp = 4;
      59                 :            :       else
      60                 :          0 :         dp = 2;
      61                 :            :     }
      62                 :          0 :   }
      63                 :            :   else
      64                 :          0 :     dp = project->readNumEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ) );
      65                 :            : 
      66                 :            :   // Keep dp sensible
      67                 :          0 :   if ( dp < 0 )
      68                 :          0 :     dp = 0;
      69                 :            : 
      70                 :          0 :   return dp;
      71                 :          0 : }
      72                 :            : 
      73                 :          0 : int QgsCoordinateUtils::calculateCoordinatePrecisionForCrs( const QgsCoordinateReferenceSystem &crs, QgsProject *project )
      74                 :            : {
      75                 :          0 :   QgsProject *prj = project;
      76                 :          0 :   if ( !prj )
      77                 :            :   {
      78                 :          0 :     prj = QgsProject::instance();
      79                 :          0 :   }
      80                 :            : 
      81                 :          0 :   bool automatic = prj->readBoolEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ) );
      82                 :          0 :   if ( !automatic )
      83                 :            :   {
      84                 :          0 :     return prj->readNumEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ), 6 );
      85                 :            :   }
      86                 :            : 
      87                 :          0 :   QgsUnitTypes::DistanceUnit unit = crs.mapUnits();
      88                 :          0 :   if ( unit == QgsUnitTypes::DistanceDegrees )
      89                 :            :   {
      90                 :          0 :     return 8;
      91                 :            :   }
      92                 :            :   else
      93                 :            :   {
      94                 :          0 :     return 3;
      95                 :            :   }
      96                 :          0 : }
      97                 :            : 
      98                 :          0 : QString QgsCoordinateUtils::formatCoordinateForProject( QgsProject *project, const QgsPointXY &point, const QgsCoordinateReferenceSystem &destCrs, int precision )
      99                 :            : {
     100                 :          0 :   if ( !project )
     101                 :          0 :     return QString();
     102                 :            : 
     103                 :          0 :   QString format = project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QStringLiteral( "MU" ) );
     104                 :            : 
     105                 :          0 :   QgsPointXY geo = point;
     106                 :          0 :   if ( format == QLatin1String( "DM" ) || format == QLatin1String( "DMS" ) || format == QLatin1String( "D" ) )
     107                 :            :   {
     108                 :            :     // degrees
     109                 :          0 :     if ( destCrs.isValid() && !destCrs.isGeographic() )
     110                 :            :     {
     111                 :            :       // need to transform to geographic coordinates
     112                 :          0 :       QgsCoordinateTransform ct( destCrs, QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ), project );
     113                 :            :       try
     114                 :            :       {
     115                 :          0 :         geo = ct.transform( point );
     116                 :          0 :       }
     117                 :            :       catch ( QgsCsException & )
     118                 :            :       {
     119                 :          0 :         return QString();
     120                 :          0 :       }
     121                 :          0 :     }
     122                 :            : 
     123                 :          0 :     if ( format == QLatin1String( "DM" ) )
     124                 :          0 :       return QgsCoordinateFormatter::format( geo, QgsCoordinateFormatter::FormatDegreesMinutes, precision, QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds | QgsCoordinateFormatter::FlagDegreesUseStringSuffix );
     125                 :          0 :     else if ( format == QLatin1String( "DMS" ) )
     126                 :          0 :       return QgsCoordinateFormatter::format( geo, QgsCoordinateFormatter::FormatDegreesMinutesSeconds, precision, QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds | QgsCoordinateFormatter::FlagDegreesUseStringSuffix );
     127                 :            :     else
     128                 :          0 :       return QgsCoordinateFormatter::asPair( geo.x(), geo.y(), precision );
     129                 :            :   }
     130                 :            :   else
     131                 :            :   {
     132                 :            :     // coordinates in map units
     133                 :          0 :     return QgsCoordinateFormatter::asPair( point.x(), point.y(), precision );
     134                 :            :   }
     135                 :          0 : }
     136                 :            : 
     137                 :          0 : QString QgsCoordinateUtils::formatExtentForProject( QgsProject *project, const QgsRectangle &extent, const QgsCoordinateReferenceSystem &destCrs, int precision )
     138                 :            : {
     139                 :          0 :   const QgsPointXY p1( extent.xMinimum(), extent.yMinimum() );
     140                 :          0 :   const QgsPointXY p2( extent.xMaximum(), extent.yMaximum() );
     141                 :          0 :   return QStringLiteral( "%1 : %2" ).arg( QgsCoordinateUtils::formatCoordinateForProject( project, p1, destCrs, precision ),
     142                 :          0 :                                           QgsCoordinateUtils::formatCoordinateForProject( project, p2, destCrs, precision ) );
     143                 :          0 : }
     144                 :            : 
     145                 :          0 : double QgsCoordinateUtils::dmsToDecimal( const QString &string, bool *ok, bool *isEasting )
     146                 :            : {
     147                 :          0 :   const QString negative( QStringLiteral( "swSW-" ) );
     148                 :          0 :   const QString easting( QStringLiteral( "eEwW" ) );
     149                 :          0 :   double value = 0.0;
     150                 :          0 :   bool okValue = false;
     151                 :            : 
     152                 :          0 :   if ( ok )
     153                 :            :   {
     154                 :          0 :     *ok = false;
     155                 :          0 :   }
     156                 :            :   else
     157                 :            :   {
     158                 :          0 :     ok = &okValue;
     159                 :            :   }
     160                 :            : 
     161                 :          0 :   QRegularExpression dms( "^\\s*(?:([-+nsew])\\s*)?(\\d{1,3})(?:[^0-9.]+([0-5]?\\d))?[^0-9.]+([0-5]?\\d(?:\\.\\d+)?)[^0-9.,]*?([-+nsew])?\\s*$", QRegularExpression::CaseInsensitiveOption );
     162                 :          0 :   QRegularExpressionMatch match = dms.match( string.trimmed() );
     163                 :          0 :   if ( match.hasMatch() )
     164                 :            :   {
     165                 :          0 :     QString dms1 = match.captured( 2 );
     166                 :          0 :     QString dms2 = match.captured( 3 );
     167                 :          0 :     QString dms3 = match.captured( 4 );
     168                 :            : 
     169                 :          0 :     double v = dms3.toDouble( ok );
     170                 :          0 :     if ( *ok == false )
     171                 :          0 :       return value;
     172                 :            :     // Allow for Degrees/minutes format as well as DMS
     173                 :          0 :     if ( !dms2.isEmpty() )
     174                 :            :     {
     175                 :          0 :       v = dms2.toInt( ok ) + v / 60.0;
     176                 :          0 :       if ( *ok == false )
     177                 :          0 :         return value;
     178                 :          0 :     }
     179                 :          0 :     v = dms1.toInt( ok ) + v / 60.0;
     180                 :          0 :     if ( *ok == false )
     181                 :          0 :       return value;
     182                 :            : 
     183                 :          0 :     QString sign1 = match.captured( 1 );
     184                 :          0 :     QString sign2 = match.captured( 5 );
     185                 :            : 
     186                 :          0 :     if ( sign1.isEmpty() )
     187                 :            :     {
     188                 :          0 :       value = !sign2.isEmpty() && negative.contains( sign2 ) ? -v : v;
     189                 :          0 :       if ( isEasting )
     190                 :            :       {
     191                 :          0 :         *isEasting = easting.contains( sign2 );
     192                 :          0 :       }
     193                 :          0 :     }
     194                 :          0 :     else if ( sign2.isEmpty() )
     195                 :            :     {
     196                 :          0 :       value = !sign1.isEmpty() && negative.contains( sign1 ) ? -v : v;
     197                 :          0 :       if ( isEasting )
     198                 :            :       {
     199                 :          0 :         *isEasting = easting.contains( sign2 );
     200                 :          0 :       }
     201                 :          0 :     }
     202                 :            :     else
     203                 :            :     {
     204                 :          0 :       *ok = false;
     205                 :            :     }
     206                 :          0 :   }
     207                 :          0 :   return value;
     208                 :          0 : }
     209                 :            : 
     210                 :            : ///@endcond

Generated by: LCOV version 1.14