Skip to content

Commit

Permalink
Add QgsCoordinateReferenceSystem::isDynamic()
Browse files Browse the repository at this point in the history
Returns TRUE if the given proj coordinate system is a dynamic CRS.

A dynamic CRS relies on a dynamic datum, that is a datum that is no
plate-fixed.
  • Loading branch information
nyalldawson committed May 10, 2021
1 parent e2e469d commit 9e7e0d4
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 0 deletions.
Expand Up @@ -791,6 +791,16 @@ overridden with these.
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)

:return: ``True`` if CRS is geographic, or ``False`` if it is a projected CRS
%End

bool isDynamic() const;
%Docstring
Returns ``True`` if the CRS is a dynamic CRS.

A dynamic CRS relies on a dynamic datum, that is a datum that is not
plate-fixed.

.. versionadded:: 3.20
%End

QgsDatumEnsemble datumEnsemble() const throw( QgsNotSupportedException );
Expand Down
9 changes: 9 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.cpp
Expand Up @@ -1197,6 +1197,15 @@ bool QgsCoordinateReferenceSystem::isGeographic() const
return d->mIsGeographic;
}

bool QgsCoordinateReferenceSystem::isDynamic() const
{
const PJ *pj = projObject();
if ( !pj )
return false;

return QgsProjUtils::isDynamic( pj );
}

QgsDatumEnsemble QgsCoordinateReferenceSystem::datumEnsemble() const
{
QgsDatumEnsemble res;
Expand Down
10 changes: 10 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.h
Expand Up @@ -732,6 +732,16 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
*/
bool isGeographic() const;

/**
* Returns TRUE if the CRS is a dynamic CRS.
*
* A dynamic CRS relies on a dynamic datum, that is a datum that is not
* plate-fixed.
*
* \since QGIS 3.20
*/
bool isDynamic() const;

/**
* Attempts to retrieve datum ensemble details from the CRS.
*
Expand Down
42 changes: 42 additions & 0 deletions src/core/proj/qgsprojutils.cpp
Expand Up @@ -139,6 +139,48 @@ bool QgsProjUtils::axisOrderIsSwapped( const PJ *crs )
return false;
}

bool QgsProjUtils::isDynamic( const PJ *crs )
{
// ported from GDAL OGRSpatialReference::IsDynamic()
bool isDynamic = false;
PJ_CONTEXT *context = QgsProjContext::get();

proj_pj_unique_ptr horiz = crsToSingleCrs( crs );

proj_pj_unique_ptr datum( horiz ? proj_crs_get_datum( context, horiz.get() ) : nullptr );
if ( datum )
{
const PJ_TYPE type = proj_get_type( datum.get() );
isDynamic = type == PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME ||
type == PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME;
if ( !isDynamic )
{
const QString authName( proj_get_id_auth_name( datum.get(), 0 ) );
const QString code( proj_get_id_code( datum.get(), 0 ) );
if ( authName == QLatin1String( "EPSG" ) && code == QLatin1String( "6326" ) )
{
isDynamic = true;
}
}
}
#if PROJ_VERSION_MAJOR > 7 || (PROJ_VERSION_MAJOR == 7 && PROJ_VERSION_MINOR >= 2)
else
{
proj_pj_unique_ptr ensemble( horiz ? proj_crs_get_datum_ensemble( context, horiz.get() ) : nullptr );
if ( ensemble )
{
proj_pj_unique_ptr member( proj_datum_ensemble_get_member( context, ensemble.get(), 0 ) );
if ( member )
{
const PJ_TYPE type = proj_get_type( member.get() );
isDynamic = type == PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME ||
type == PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME;
}
}
}
#endif
return isDynamic;
}

QgsProjUtils::proj_pj_unique_ptr QgsProjUtils::crsToSingleCrs( const PJ *crs )
{
Expand Down
10 changes: 10 additions & 0 deletions src/core/proj/qgsprojutils.h
Expand Up @@ -147,6 +147,16 @@ class CORE_EXPORT QgsProjUtils
*/
static bool axisOrderIsSwapped( const PJ *crs );

/**
* Returns TRUE if the given proj coordinate system is a dynamic CRS.
*
* A dynamic CRS relies on a dynamic datum, that is a datum that is not
* plate-fixed.
*
* \since QGIS 3.20
*/
static bool isDynamic( const PJ *crs );

/**
* Given a PROJ crs (which may be a compound or bound crs, or some other type), extract a single crs
* from it.
Expand Down
36 changes: 36 additions & 0 deletions tests/src/core/testqgscoordinatereferencesystem.cpp
Expand Up @@ -77,6 +77,7 @@ class TestQgsCoordinateReferenceSystem: public QObject
void toProj();
void isGeographic();
void mapUnits();
void isDynamic();
void setValidationHint();
void hasAxisInverted();
void createFromProjInvalid();
Expand Down Expand Up @@ -1200,6 +1201,41 @@ void TestQgsCoordinateReferenceSystem::mapUnits()
// an invalid crs should return unknown unit
QCOMPARE( QgsCoordinateReferenceSystem().mapUnits(), QgsUnitTypes::DistanceUnknownUnit );
}

void TestQgsCoordinateReferenceSystem::isDynamic()
{
#if (PROJ_VERSION_MAJOR>7 || (PROJ_VERSION_MAJOR==7 && PROJ_VERSION_MINOR >= 2 ) )
QgsCoordinateReferenceSystem crs( QStringLiteral( "EPSG:7665" ) );
QVERIFY( crs.isDynamic() );

crs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4171" ) );
QVERIFY( !crs.isDynamic() );

// WGS84 (generic), using datum ensemble
crs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) );
QVERIFY( crs.isDynamic() );

// ETRS89 (generic), using datum ensemble
crs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4258" ) );
QVERIFY( !crs.isDynamic() );

QVERIFY( crs.createFromWkt( QStringLiteral( R"""(GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
AUTHORITY["EPSG","9122"]],
AXIS["Latitude",NORTH],
AXIS["Longitude",EAST],
AUTHORITY["EPSG","4326"]])""" ) ) );
QVERIFY( crs.isValid() );
QVERIFY( crs.isDynamic() );
#endif
}

void TestQgsCoordinateReferenceSystem::setValidationHint()
{
QgsCoordinateReferenceSystem myCrs;
Expand Down

0 comments on commit 9e7e0d4

Please sign in to comment.