Skip to content
Permalink
Browse files
Move ellipsoid parameter retrieval to new QgsEllipsoidUtils class
  • Loading branch information
nyalldawson committed Apr 17, 2017
1 parent cc5b9bf commit 147bb7f1ed0292ea379c1156c8de1c862415fe5e
@@ -47,6 +47,7 @@
%Include qgsdistancearea.sip
%Include qgseditformconfig.sip
%Include qgseditorwidgetsetup.sip
%Include qgsellipsoidutils.sip
%Include qgserror.sip
%Include qgsexpression.sip
%Include qgsexpressioncontext.sip
@@ -0,0 +1,72 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsellipsoidutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



class QgsEllipsoidUtils
{
%Docstring
Contains utility functions for working with ellipsoids and querying the ellipsoid database.

.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsellipsoidutils.h"
%End
public:

struct EllipsoidParameters
{
bool valid;
%Docstring
Whether ellipsoid parameters are valid
%End

double semiMajor;
%Docstring
Semi-major axis
%End
double semiMinor;
%Docstring
Semi-minor axis
%End

bool useCustomParameters;
%Docstring
Whether custom parameters alone should be used (semiMajor/semiMinor only)
%End

double inverseFlattening;
%Docstring
Inverse flattening
%End

QgsCoordinateReferenceSystem crs;
%Docstring
Associated coordinate reference system
%End
};

static EllipsoidParameters ellipsoidParameters( const QString &ellipsoid );
%Docstring
Returns the parameters for the specified ``ellipsoid``.
Results are cached to allow for fast retrieval of parameters.
:rtype: EllipsoidParameters
%End

};


/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsellipsoidutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
@@ -369,6 +369,12 @@ sub processDoxygenLine
$line = $newline;
}

# remove inline declarations
if ( $line =~ m/^(\s*)?(static |const )*(([\w:]+(<.*?>)?\s+(\*|&)?)?(\w+)( (?:const*?))*)\s*(\{.*\});(\s*\/\/.*)?$/ ){
my $newline = "$1$3;\n";
$line = $newline;
}

if ( $line =~ m/^\s*(?:const |virtual |static |inline )*(?!explicit)([\w:]+(?:<.*?>)?)\s+(?:\*|&)?(?:\w+|operator.{1,2})\(.*$/ ){
if ($1 !~ m/(void|SIP_PYOBJECT|operator|return|QFlag)/ ){
$return_type = $1;
@@ -128,6 +128,7 @@ SET(QGIS_CORE_SRCS
qgsdiagramrenderer.cpp
qgsdistancearea.cpp
qgseditformconfig.cpp
qgsellipsoidutils.cpp
qgserror.cpp
qgsexpression.cpp
qgsexpressioncontext.cpp
@@ -699,18 +700,19 @@ SET(QGIS_CORE_HDRS
qgsdistancearea.h
qgseditformconfig.h
qgseditorwidgetsetup.h
qgsfeaturefilterprovider.h
qgsfield_p.h
qgsellipsoidutils.h
qgserror.h
qgsexception.h
qgsexpression.h
qgsexpressioncontext.h
qgsexpressioncontextgenerator.h
qgsexpressionfieldbuffer.h
qgsfeaturefilterprovider.h
qgsfeatureiterator.h
qgsfeaturerequest.h
qgsfeaturestore.h
qgsfieldformatter.h
qgsfield_p.h
qgsfields.h
qgsfontutils.h
qgsgeometrycache.h
@@ -14,19 +14,16 @@
***************************************************************************/

#include <cmath>
#include <sqlite3.h>
#include <QDir>
#include <QString>
#include <QObject>

#include "qgsdistancearea.h"
#include "qgis.h"
#include "qgspoint.h"
#include "qgscoordinatetransform.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsgeometry.h"
#include "qgsgeometrycollection.h"
#include "qgsdistancearea.h"
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgsmultisurface.h"
@@ -46,9 +43,6 @@
#define RAD2DEG(r) (180.0 * (r) / M_PI)
#define POW2(x) ((x)*(x))

QReadWriteLock QgsDistanceArea::sEllipsoidCacheLock;
QHash< QString, QgsDistanceArea::EllipsoidParameters > QgsDistanceArea::sEllipsoidCache;

QgsDistanceArea::QgsDistanceArea()
{
// init with default settings
@@ -75,172 +69,22 @@ bool QgsDistanceArea::setEllipsoid( const QString &ellipsoid )
return true;
}

// check cache
sEllipsoidCacheLock.lockForRead();
QHash< QString, EllipsoidParameters >::const_iterator cacheIt = sEllipsoidCache.constFind( ellipsoid );
if ( cacheIt != sEllipsoidCache.constEnd() )
{
// found a match in the cache
bool result = cacheIt.value().valid;
if ( result )
{
mEllipsoid = ellipsoid;
setFromParams( cacheIt.value() );
}
sEllipsoidCacheLock.unlock();
return result;
}
sEllipsoidCacheLock.unlock();

EllipsoidParameters params;

// Check if we have a custom projection, and set from text string.
// Format is "PARAMETER:<semi-major axis>:<semi minor axis>
// Numbers must be with (optional) decimal point and no other separators (C locale)
// Distances in meters. Flattening is calculated.
if ( ellipsoid.startsWith( QLatin1String( "PARAMETER" ) ) )
{
QStringList paramList = ellipsoid.split( ':' );
bool semiMajorOk, semiMinorOk;
double semiMajor = paramList[1].toDouble( & semiMajorOk );
double semiMinor = paramList[2].toDouble( & semiMinorOk );
if ( semiMajorOk && semiMinorOk )
{
params.semiMajor = semiMajor;
params.semiMinor = semiMinor;
params.useCustomParameters = true;
}
else
{
params.valid = false;
}

sEllipsoidCacheLock.lockForWrite();
sEllipsoidCache.insert( ellipsoid, params );
sEllipsoidCacheLock.unlock();
if ( params.valid )
setFromParams( params );
return params.valid;
}

// cache miss - get from database

QString radius, parameter2;
//
// SQLITE3 stuff - get parameters for selected ellipsoid
//
sqlite3 *database = nullptr;
const char *tail = nullptr;
sqlite3_stmt *preparedStatement = nullptr;
// Continue with PROJ.4 list of ellipsoids.

//check the db is available
int result = sqlite3_open_v2( QgsApplication::srsDatabaseFilePath().toUtf8().data(), &database, SQLITE_OPEN_READONLY, nullptr );
if ( result )
{
QgsMessageLog::logMessage( QObject::tr( "Can't open database: %1" ).arg( sqlite3_errmsg( database ) ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
return false;
}
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString sql = "select radius, parameter2 from tbl_ellipsoid where acronym='" + ellipsoid + '\'';
result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &preparedStatement, &tail );
// XXX Need to free memory from the error msg if one is set
if ( result == SQLITE_OK )
{
if ( sqlite3_step( preparedStatement ) == SQLITE_ROW )
{
radius = QString( reinterpret_cast< const char * >( sqlite3_column_text( preparedStatement, 0 ) ) );
parameter2 = QString( reinterpret_cast< const char * >( sqlite3_column_text( preparedStatement, 1 ) ) );
}
}
// close the sqlite3 statement
sqlite3_finalize( preparedStatement );
sqlite3_close( database );

// row for this ellipsoid wasn't found?
if ( radius.isEmpty() || parameter2.isEmpty() )
QgsEllipsoidUtils::EllipsoidParameters params = QgsEllipsoidUtils::ellipsoidParameters( ellipsoid );
if ( !params.valid )
{
QgsDebugMsg( QString( "setEllipsoid: no row in tbl_ellipsoid for acronym '%1'" ).arg( ellipsoid ) );
params.valid = false;
sEllipsoidCacheLock.lockForWrite();
sEllipsoidCache.insert( ellipsoid, params );
sEllipsoidCacheLock.unlock();
return false;
}

// get major semiaxis
if ( radius.left( 2 ) == QLatin1String( "a=" ) )
params.semiMajor = radius.midRef( 2 ).toDouble();
else
{
QgsDebugMsg( QString( "setEllipsoid: wrong format of radius field: '%1'" ).arg( radius ) );
params.valid = false;
sEllipsoidCacheLock.lockForWrite();
sEllipsoidCache.insert( ellipsoid, params );
sEllipsoidCacheLock.unlock();
return false;
}

// get second parameter
// one of values 'b' or 'f' is in field parameter2
// second one must be computed using formula: invf = a/(a-b)
if ( parameter2.left( 2 ) == QLatin1String( "b=" ) )
{
params.semiMinor = parameter2.midRef( 2 ).toDouble();
params.inverseFlattening = params.semiMajor / ( params.semiMajor - params.semiMinor );
}
else if ( parameter2.left( 3 ) == QLatin1String( "rf=" ) )
{
params.inverseFlattening = parameter2.midRef( 3 ).toDouble();
params.semiMinor = params.semiMajor - ( params.semiMajor / params.inverseFlattening );
}
else
{
QgsDebugMsg( QString( "setEllipsoid: wrong format of parameter2 field: '%1'" ).arg( parameter2 ) );
params.valid = false;
sEllipsoidCacheLock.lockForWrite();
sEllipsoidCache.insert( ellipsoid, params );
sEllipsoidCacheLock.unlock();
return false;
}

QgsDebugMsg( QString( "setEllipsoid: a=%1, b=%2, 1/f=%3" ).arg( params.semiMajor ).arg( params.semiMinor ).arg( params.inverseFlattening ) );


// get spatial ref system for ellipsoid
QString proj4 = "+proj=longlat +ellps=" + ellipsoid + " +no_defs";
QgsCoordinateReferenceSystem destCRS = QgsCoordinateReferenceSystem::fromProj4( proj4 );
//TODO: createFromProj4 used to save to the user database any new CRS
// this behavior was changed in order to separate creation and saving.
// Not sure if it necessary to save it here, should be checked by someone
// familiar with the code (should also give a more descriptive name to the generated CRS)
if ( destCRS.srsid() == 0 )
{
QString name = QStringLiteral( " * %1 (%2)" )
.arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ),
destCRS.toProj4() );
destCRS.saveAsUserCrs( name );
mEllipsoid = ellipsoid;
setFromParams( params );
return true;
}
//

// set transformation from project CRS to ellipsoid coordinates
params.crs = destCRS;

sEllipsoidCacheLock.lockForWrite();
sEllipsoidCache.insert( ellipsoid, params );
sEllipsoidCacheLock.unlock();

mEllipsoid = ellipsoid;

setFromParams( params );
return true;
}

// Inverse flattening is calculated with invf = a/(a-b)
// Also, b = a-(a/invf)
bool QgsDistanceArea::setEllipsoid( double semiMajor, double semiMinor )
bool QgsDistanceArea::setEllipsoid( double semiMajor, double semiMinor )
{
mEllipsoid = QStringLiteral( "PARAMETER:%1:%2" ).arg( qgsDoubleToString( semiMajor ) ).arg( qgsDoubleToString( semiMinor ) );
mSemiMajor = semiMajor;
@@ -806,7 +650,7 @@ void QgsDistanceArea::computeAreaInit()
m_E = -m_E;
}

void QgsDistanceArea::setFromParams( const QgsDistanceArea::EllipsoidParameters &params )
void QgsDistanceArea::setFromParams( const QgsEllipsoidUtils::EllipsoidParameters &params )
{
if ( params.useCustomParameters )
{
@@ -21,6 +21,7 @@
#include <QReadWriteLock>
#include "qgscoordinatetransform.h"
#include "qgsunittypes.h"
#include "qgsellipsoidutils.h"

class QgsGeometry;
class QgsAbstractGeometry;
@@ -312,30 +313,7 @@ class CORE_EXPORT QgsDistanceArea
*/
void computeAreaInit();

/**
* Contains parameter definitions for an ellipsoid.
* \since QGIS 3.0
*/
struct EllipsoidParameters
{
//! Whether ellipsoid parameters are valid
bool valid = true;

//! Semi-major axis
double semiMajor = -1.0;
//! Semi-minor axis
double semiMinor = -1.0;

//! Whether custom parameters alone should be used (semiMajor/semiMinor only)
bool useCustomParameters = false;

//! Inverse flattening
double inverseFlattening = -1.0;
//! Associated coordinate reference system
QgsCoordinateReferenceSystem crs;
};

void setFromParams( const EllipsoidParameters &params );
void setFromParams( const QgsEllipsoidUtils::EllipsoidParameters &params );

enum MeasureType
{
@@ -371,10 +349,6 @@ class CORE_EXPORT QgsDistanceArea
double m_E; /* area of the earth */
double m_TwoPI;

// ellipsoid cache
static QReadWriteLock sEllipsoidCacheLock;
static QHash< QString, EllipsoidParameters > sEllipsoidCache;

};

#endif
Loading

0 comments on commit 147bb7f

Please sign in to comment.