Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add method to create QgsCoordinateReferenceSystem from proj object
  • Loading branch information
nyalldawson committed Jan 11, 2022
1 parent 8896eb7 commit e504be4
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.cpp
Expand Up @@ -2630,6 +2630,75 @@ PJ *QgsCoordinateReferenceSystem::projObject() const
return d->threadLocalProjObject();
}

QgsCoordinateReferenceSystem QgsCoordinateReferenceSystem::fromProjObject( PJ *object )
{
QgsCoordinateReferenceSystem crs;
crs.createFromProjObject( object );
return crs;
}

bool QgsCoordinateReferenceSystem::createFromProjObject( PJ *object )
{
d.detach();
d->mIsValid = false;
d->mProj4.clear();
d->mWktPreferred.clear();

if ( !object )
{
return false;
}

switch ( proj_get_type( object ) )
{
case PJ_TYPE_VERTICAL_CRS:
case PJ_TYPE_PRIME_MERIDIAN:
case PJ_TYPE_ELLIPSOID:
case PJ_TYPE_GEODETIC_REFERENCE_FRAME:
case PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME:
case PJ_TYPE_VERTICAL_REFERENCE_FRAME:
case PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME:
case PJ_TYPE_DATUM_ENSEMBLE:
case PJ_TYPE_CONVERSION:
case PJ_TYPE_TRANSFORMATION:
case PJ_TYPE_CONCATENATED_OPERATION:
case PJ_TYPE_OTHER_COORDINATE_OPERATION:
case PJ_TYPE_TEMPORAL_DATUM:
case PJ_TYPE_ENGINEERING_DATUM:
case PJ_TYPE_PARAMETRIC_DATUM:
return false;

default:
break;
}

d->setPj( QgsProjUtils::crsToSingleCrs( object ) );

if ( !d->hasPj() )
{
return d->mIsValid;
}
else
{
// maybe we can directly grab the auth name and code from the crs
const QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
const QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
if ( !authName.isEmpty() && !authCode.isEmpty() && loadFromAuthCode( authName, authCode ) )
{
return d->mIsValid;
}
else
{
// Still a valid CRS, just not a known one
d->mIsValid = true;
d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
setMapUnits();
}
}

return d->mIsValid;
}

QStringList QgsCoordinateReferenceSystem::recentProjections()
{
QStringList projections;
Expand Down
22 changes: 22 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.h
Expand Up @@ -932,6 +932,28 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
* \since QGIS 3.8
*/
PJ *projObject() const;

/**
* Constructs a QgsCoordinateReferenceSystem from a PROJ PJ object.
*
* The \a object must correspond to a PROJ CRS object.
*
* Ownership of \a object is not transferred.
*
* \note Not available in Python bindings
* \since QGIS 3.24
*/
static QgsCoordinateReferenceSystem fromProjObject( PJ *object );

/**
* Sets this CRS by passing it a PROJ PJ \a object, corresponding to a PROJ CRS object.
*
* Ownership of \a object is not transferred.
*
* \note Not available in Python bindings
* \since QGIS 3.24
*/
bool createFromProjObject( PJ *object );
#endif

/**
Expand Down
85 changes: 85 additions & 0 deletions tests/src/core/testqgscoordinatereferencesystem.cpp
Expand Up @@ -63,6 +63,9 @@ class TestQgsCoordinateReferenceSystem: public QObject
void proj4Cache();
void fromString();
void fromStringCache();
void fromProjObject();
void fromProjObjectKnownCrs();
void fromProjObjectNotCrs();
void isValid();
void validate();
void comparison_data();
Expand Down Expand Up @@ -767,6 +770,88 @@ void TestQgsCoordinateReferenceSystem::fromStringCache()
QVERIFY( !QgsCoordinateReferenceSystem::stringCache().contains( QStringLiteral( "EPSG:3113" ) ) );
}

void TestQgsCoordinateReferenceSystem::fromProjObject()
{
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromProjObject( nullptr );
QVERIFY( !crs.isValid() );

// test creating a QgsCoordinateReferenceSystem from a proj object which is custom crs
const QString def = QStringLiteral( "+proj=ortho +lat_0=-20 +lon_0=11.11111 +x_0=0 +y_0=0 +R=6371000 +units=m +no_defs +type=crs" );
const QgsProjUtils::proj_pj_unique_ptr pj( proj_create( QgsProjContext::get(), def.toUtf8().constData() ) );
QVERIFY( pj.get() );

crs = QgsCoordinateReferenceSystem::fromProjObject( pj.get() );
QVERIFY( crs.isValid() );
QCOMPARE( crs.authid(), QString() );
QCOMPARE( crs.toProj(), QStringLiteral( "+proj=ortho +lat_0=-20 +lon_0=11.11111 +x_0=0 +y_0=0 +R=6371000 +units=m +no_defs +type=crs" ) );
}

void TestQgsCoordinateReferenceSystem::fromProjObjectKnownCrs()
{
// test creating a QgsCoordinateReferenceSystem from a proj object which is known crs
const QString crsWkt = QStringLiteral( R"""(
PROJCRS["GDA94 / Vicgrid",
BASEGEOGCRS["GDA94",
DATUM["Geocentric Datum of Australia 1994",
ELLIPSOID["GRS 1980",6378137,298.257222101,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4283]],
CONVERSION["Vicgrid",
METHOD["Lambert Conic Conformal (2SP)",
ID["EPSG",9802]],
PARAMETER["Latitude of false origin",-37,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8821]],
PARAMETER["Longitude of false origin",145,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8822]],
PARAMETER["Latitude of 1st standard parallel",-36,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8823]],
PARAMETER["Latitude of 2nd standard parallel",-38,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8824]],
PARAMETER["Easting at false origin",2500000,
LENGTHUNIT["metre",1],
ID["EPSG",8826]],
PARAMETER["Northing at false origin",2500000,
LENGTHUNIT["metre",1],
ID["EPSG",8827]]],
CS[Cartesian,2],
AXIS["(E)",east,
ORDER[1],
LENGTHUNIT["metre",1]],
AXIS["(N)",north,
ORDER[2],
LENGTHUNIT["metre",1]],
USAGE[
SCOPE["State-wide spatial data management."],
AREA["Australia - Victoria."],
BBOX[-39.2,140.96,-33.98,150.04]],
ID["EPSG",3111]]
)""" );

const QgsProjUtils::proj_pj_unique_ptr pj( proj_create_from_wkt( QgsProjContext::get(), crsWkt.toUtf8().constData(), nullptr, nullptr, nullptr ) );
QVERIFY( pj.get() );

QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromProjObject( pj.get() );
QVERIFY( crs.isValid() );
QCOMPARE( crs.authid(), QStringLiteral( "EPSG:3111" ) );
}

void TestQgsCoordinateReferenceSystem::fromProjObjectNotCrs()
{
// test creating a QgsCoordinateReferenceSystem from a proj object which is NOT a crs
const QString operation = QStringLiteral( "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=utm +zone=56 +south +ellps=GRS80" );
const QgsProjUtils::proj_pj_unique_ptr pj( proj_create( QgsProjContext::get(), operation.toUtf8().constData() ) );
QVERIFY( pj.get() );

QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromProjObject( pj.get() );
QVERIFY( !crs.isValid() );
}

void TestQgsCoordinateReferenceSystem::isValid()
{
QgsCoordinateReferenceSystem crs( QStringLiteral( "EPSG:4326" ) );
Expand Down

0 comments on commit e504be4

Please sign in to comment.