Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,22 @@ int main( int argc, char *argv[] )
pk->setVerticalCrs( crs );

// read and set new elevation transformation behavior
// The project key was previously named "SkipElevationTransformation" (skip=true meant no transformation).
// It was replaced by "ElevationTransformationEnabled" with inverted logic (enabled=true means transformation is done).
// Both keys are supported for backwards compatibility — "ElevationTransformationEnabled" takes precedence if present.
bool valueRead = false;
const bool skipElevationTransformation = project->readBoolEntry( QStringLiteral( "Mergin" ), QStringLiteral( "SkipElevationTransformation" ), true, &valueRead );
pk->setSkipElevationTransformation( skipElevationTransformation );
const bool elevationTransformationEnabled = project->readBoolEntry( QStringLiteral( "Mergin" ), QStringLiteral( "ElevationTransformationEnabled" ), false, &valueRead );
bool transformationEnabled = false;
if ( valueRead )
{
transformationEnabled = elevationTransformationEnabled;
}
else
{
// old key used inverted logic: skip=true meant transformation was disabled
transformationEnabled = !project->readBoolEntry( QStringLiteral( "Mergin" ), QStringLiteral( "SkipElevationTransformation" ), true );
}
pk->setElevationTransformationEnabled( transformationEnabled );

pk->refreshPositionTransformer( project->transformContext() );
} );
Expand Down
12 changes: 6 additions & 6 deletions app/position/positionkit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
PositionKit::PositionKit( QObject *parent )
: QObject( parent )
{
mPositionTransformer = std::make_unique<PositionTransformer>( positionCrs3DEllipsoidHeight(), positionCrs3D(), mSkipElevationTransformation, QgsCoordinateTransformContext() );
mPositionTransformer = std::make_unique<PositionTransformer>( positionCrs3DEllipsoidHeight(), positionCrs3D(), mElevationTransformationEnabled, QgsCoordinateTransformContext() );
}

QgsCoordinateReferenceSystem PositionKit::positionCrs3D()
{
if ( !mSkipElevationTransformation && mPositionCrs3D.isValid() )
if ( mElevationTransformationEnabled && mPositionCrs3D.isValid() )
{
return mPositionCrs3D;
}
Expand All @@ -45,7 +45,7 @@ QgsCoordinateReferenceSystem PositionKit::positionCrs3D()

QString PositionKit::positionCrs3DGeoidModelName()
{
if ( !mSkipElevationTransformation )
if ( mElevationTransformationEnabled )
{
return mVerticalCrs.description();
}
Expand Down Expand Up @@ -402,9 +402,9 @@ void PositionKit::setVerticalCrs( const QgsCoordinateReferenceSystem &verticalCr
mPositionCrs3D = QgsCoordinateReferenceSystem();
}

void PositionKit::setSkipElevationTransformation( const bool skipElevationTransformation )
void PositionKit::setElevationTransformationEnabled( const bool elevationTransformationEnabled )
{
mSkipElevationTransformation = skipElevationTransformation;
mElevationTransformationEnabled = elevationTransformationEnabled;
}

void PositionKit::appStateChanged( Qt::ApplicationState state )
Expand All @@ -422,7 +422,7 @@ void PositionKit::appStateChanged( Qt::ApplicationState state )
void PositionKit::refreshPositionTransformer( const QgsCoordinateTransformContext &transformContext )
{
mPositionTransformer->setDestinationCrs( positionCrs3D() );
mPositionTransformer->setSkipElevationTransformation( mSkipElevationTransformation );
mPositionTransformer->setElevationTransformationEnabled( mElevationTransformationEnabled );
mPositionTransformer->setTransformContext( transformContext );
}

Expand Down
4 changes: 2 additions & 2 deletions app/position/positionkit.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class PositionKit : public QObject
double antennaHeight() const;

void setVerticalCrs( const QgsCoordinateReferenceSystem &verticalCrs );
void setSkipElevationTransformation( bool skipElevationTransformation );
void setElevationTransformationEnabled( bool elevationTransformationEnabled );
// should be executed on active project changed, updates the CRS, elevation transformation and context properties
void refreshPositionTransformer( const QgsCoordinateTransformContext &transformContext );

Expand Down Expand Up @@ -201,7 +201,7 @@ class PositionKit : public QObject

QgsCoordinateReferenceSystem mPositionCrs3D;
QgsCoordinateReferenceSystem mVerticalCrs;
bool mSkipElevationTransformation = true;
bool mElevationTransformationEnabled = false;

friend class TestPosition;
};
Expand Down
18 changes: 9 additions & 9 deletions app/position/positiontransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@
#include "inpututils.h"

PositionTransformer::PositionTransformer( const QgsCoordinateReferenceSystem &sourceCrs,
const QgsCoordinateReferenceSystem &destinationCrs, const bool skipElevationTransformation, const QgsCoordinateTransformContext &transformContext, QObject *parent )
const QgsCoordinateReferenceSystem &destinationCrs, const bool elevationTransformationEnabled, const QgsCoordinateTransformContext &transformContext, QObject *parent )
: QObject( parent ),
mSourceCrs( sourceCrs ),
mDestinationCrs( destinationCrs ),
mTransformContext( transformContext ),
mSkipElevationTransformation( skipElevationTransformation )
mElevationTransformationEnabled( elevationTransformationEnabled )
{
}

GeoPosition PositionTransformer::processBluetoothPosition( GeoPosition geoPosition )
{
if ( !mSkipElevationTransformation && !std::isnan( geoPosition.elevation ) && !std::isnan( geoPosition.elevation_diff ) )
if ( mElevationTransformationEnabled && !std::isnan( geoPosition.elevation ) && !std::isnan( geoPosition.elevation_diff ) )
{
// The geoid models used in GNSS devices can be often times unreliable, thus we apply the transformations ourselves
// GNSS supplied orthometric elevation -> ellipsoid elevation -> orthometric elevation based on our model
Expand Down Expand Up @@ -55,7 +55,7 @@ GeoPosition PositionTransformer::processAndroidPosition( GeoPosition geoPosition
if ( geoPosition.elevation != std::numeric_limits<double>::quiet_NaN() )
{
bool positionOutsideGeoidModelArea = false;
if ( !geoPosition.isMock || !mSkipElevationTransformation )
if ( !geoPosition.isMock || mElevationTransformationEnabled )
{
const QgsPoint geoidPosition = InputUtils::transformPoint(
mSourceCrs,
Expand Down Expand Up @@ -112,7 +112,7 @@ GeoPosition PositionTransformer::processInternalIosPosition( QGeoPositionInfo &g
GeoPosition newPosition;
bool positionOutsideGeoidModelArea = false;
// on ios we can get both ellipsoid and geoid altitude, depending on what is available we transform the altitude or not
// we also check if the user set vertical CRS pass through in plugin, which prohibits any transformation
// we also check if the user has elevation transformation enabled in the project settings
const bool isEllipsoidalAltitude = geoPosition.hasAttribute( QGeoPositionInfo::VerticalSpeed );
geoPosition.removeAttribute( QGeoPositionInfo::VerticalSpeed );
const bool isMockedLocation = geoPosition.hasAttribute( QGeoPositionInfo::MagneticVariation );
Expand All @@ -123,7 +123,7 @@ GeoPosition PositionTransformer::processInternalIosPosition( QGeoPositionInfo &g

const bool isInternalProviderEllipsoidAltitude = !isMockedLocation && isEllipsoidalAltitude;
// with mocked position we expect ellipsoid elevation
if ( isInternalProviderEllipsoidAltitude || ( isMockedLocation && !mSkipElevationTransformation ) )
if ( isInternalProviderEllipsoidAltitude || ( isMockedLocation && mElevationTransformationEnabled ) )
{
geoidPosition = InputUtils::transformPoint(
mSourceCrs,
Expand Down Expand Up @@ -152,7 +152,7 @@ GeoPosition PositionTransformer::processInternalIosPosition( QGeoPositionInfo &g
// - on iOS - it would return MSL altitude, but we have a custom patch in vcpkg to return
// ellipsoid altitude, if it's available (so we do not rely on geoid model of unknown quality/resolution),
// or we get orthometric altitude from mocked location, but the altitude separation is unknown
if ( isInternalProviderEllipsoidAltitude || ( isMockedLocation && !mSkipElevationTransformation ) )
if ( isInternalProviderEllipsoidAltitude || ( isMockedLocation && mElevationTransformationEnabled ) )
{
const double ellipsoidAltitude = geoPosition.coordinate().altitude();
const double geoidSeparation = ellipsoidAltitude - geoidPosition.z();
Expand Down Expand Up @@ -209,7 +209,7 @@ void PositionTransformer::setTransformContext( const QgsCoordinateTransformConte
mTransformContext = transformContext;
}

void PositionTransformer::setSkipElevationTransformation( const bool skipElevationTransformation )
void PositionTransformer::setElevationTransformationEnabled( const bool elevationTransformationEnabled )
{
mSkipElevationTransformation = skipElevationTransformation;
mElevationTransformationEnabled = elevationTransformationEnabled;
}
10 changes: 5 additions & 5 deletions app/position/positiontransformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ class PositionTransformer : QObject
{
Q_OBJECT
public:
PositionTransformer( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, bool skipElevationTransformation, const QgsCoordinateTransformContext &transformContext, QObject *parent = nullptr );
PositionTransformer( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, bool elevationTransformationEnabled, const QgsCoordinateTransformContext &transformContext, QObject *parent = nullptr );

/**
* Transform the elevation from EPSG:4979 (WGS84 (EPSG:4326) + ellipsoidal height) to specified geoid model
* (by default EPSG:9707 (WGS84 + EGM96))
* Transform only if:
* 1. the position is not mocked, and it's ellipsoidal elevation
* 2. the position is mocked, the elevation is ellipsoidal plus pass through is disabled
* 2. the position is mocked, the elevation is ellipsoidal and elevation transformation is enabled
* \note This method should be used only with AndroidPositionProvider, which guarantees the elevation to be ellipsoid
* \return Copy of passed geoPosition with processed elevation and elevation separation if applicable.
*/
Expand Down Expand Up @@ -69,7 +69,7 @@ class PositionTransformer : QObject
* (by default EPSG:9707 (WGS84 + EGM96))
* Transform only if:
* 1. the position is not mocked, and it's ellipsoidal elevation
* 2. the position is mocked, the elevation is ellipsoidal plus pass through is disabled
* 2. the position is mocked, the elevation is ellipsoidal and elevation transformation is enabled
* \note The function gets passed reference to geoPosition, because we use some QGeoPositionInfo attributes
* to find out if the position is mocked and if the elevation is ellipsoid or orthometric.
* \return New GeoPosition with processed elevation and elevation separation if applicable.
Expand All @@ -90,13 +90,13 @@ class PositionTransformer : QObject

void setTransformContext( const QgsCoordinateTransformContext &transformContext );

void setSkipElevationTransformation( bool skipElevationTransformation );
void setElevationTransformationEnabled( bool elevationTransformationEnabled );

private:
QgsCoordinateReferenceSystem mSourceCrs;
QgsCoordinateReferenceSystem mDestinationCrs;
QgsCoordinateTransformContext mTransformContext;
bool mSkipElevationTransformation;
bool mElevationTransformationEnabled;
};


Expand Down
40 changes: 20 additions & 20 deletions app/test/testposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,8 @@ void TestPosition::testPositionTransformerAndroidPosition()
QgsCoordinateReferenceSystem ellipsoidHeightCrs = QgsCoordinateReferenceSystem::fromEpsgId( 4979 );
// WGS84 + EGM96
QgsCoordinateReferenceSystem geoidHeightCrs = QgsCoordinateReferenceSystem::fromEpsgId( 9707 );
PositionTransformer passThroughTransformer( ellipsoidHeightCrs, geoidHeightCrs, true, QgsCoordinateTransformContext() );
PositionTransformer positionTransformer( ellipsoidHeightCrs, geoidHeightCrs, false, QgsCoordinateTransformContext() );
PositionTransformer disabledTransformer( ellipsoidHeightCrs, geoidHeightCrs, false, QgsCoordinateTransformContext() );
PositionTransformer positionTransformer( ellipsoidHeightCrs, geoidHeightCrs, true, QgsCoordinateTransformContext() );

#ifdef HAVE_BLUETOOTH
// mini file contains only minimal info like position and date
Expand All @@ -522,24 +522,24 @@ void TestPosition::testPositionTransformerAndroidPosition()
geoPosition.elevation = 171.3;
#endif

// transform with pass through enabled, but position is not mocked
GeoPosition newPosition = passThroughTransformer.processAndroidPosition( geoPosition );
// transform with transformation disabled, but position is not mocked (real positions are always transformed)
GeoPosition newPosition = disabledTransformer.processAndroidPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
QVERIFY( qgsDoubleNear( newPosition.longitude, 17.1064 ) );
QVERIFY( qgsDoubleNear( newPosition.elevation, 127.53574931171875 ) );
QVERIFY( qgsDoubleNear( newPosition.elevation_diff, 43.764250688281265 ) );

// transform with pass through enabled, position is mocked
// transform with transformation disabled, position is mocked (mocked positions are passed through)
geoPosition.isMock = true;
newPosition = passThroughTransformer.processAndroidPosition( geoPosition );
newPosition = disabledTransformer.processAndroidPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
QVERIFY( qgsDoubleNear( newPosition.longitude, 17.1064 ) );
QCOMPARE( newPosition.elevation, 171.3 );
QCOMPARE( newPosition.elevation_diff, std::numeric_limits<double>::quiet_NaN() );

// transform with pass through disabled, position is mocked
// transform with transformation enabled, position is mocked
newPosition = positionTransformer.processAndroidPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
Expand All @@ -555,8 +555,8 @@ void TestPosition::testPositionTransformerBluetoothPosition()
QgsCoordinateReferenceSystem ellipsoidHeightCrs = QgsCoordinateReferenceSystem::fromEpsgId( 4979 );
// WGS84 + EGM96
QgsCoordinateReferenceSystem geoidHeightCrs = QgsCoordinateReferenceSystem::fromEpsgId( 9707 );
PositionTransformer passThroughTransformer( ellipsoidHeightCrs, geoidHeightCrs, true, QgsCoordinateTransformContext() );
PositionTransformer positionTransformer( ellipsoidHeightCrs, geoidHeightCrs, false, QgsCoordinateTransformContext() );
PositionTransformer disabledTransformer( ellipsoidHeightCrs, geoidHeightCrs, false, QgsCoordinateTransformContext() );
PositionTransformer positionTransformer( ellipsoidHeightCrs, geoidHeightCrs, true, QgsCoordinateTransformContext() );

#ifdef HAVE_BLUETOOTH
// mini file contains only minimal info like position and date
Expand All @@ -581,32 +581,32 @@ void TestPosition::testPositionTransformerBluetoothPosition()
geoPosition.elevation = 171.3;
#endif

// transform with pass through disabled and missing elevation separation
// transform with transformation enabled and missing elevation separation (no-op without elevation_diff)
GeoPosition newPosition = positionTransformer.processBluetoothPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
QVERIFY( qgsDoubleNear( newPosition.longitude, 17.1064 ) );
QCOMPARE( newPosition.elevation, 171.3 );
QCOMPARE( newPosition.elevation_diff, std::numeric_limits<double>::quiet_NaN() );

// transform with pass through enabled and missing elevation separation
newPosition = passThroughTransformer.processBluetoothPosition( geoPosition );
// transform with transformation disabled and missing elevation separation
newPosition = disabledTransformer.processBluetoothPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
QVERIFY( qgsDoubleNear( newPosition.longitude, 17.1064 ) );
QCOMPARE( newPosition.elevation, 171.3 );
QCOMPARE( newPosition.elevation_diff, std::numeric_limits<double>::quiet_NaN() );

// transform with pass through enabled and elevation separation
// transform with transformation disabled and elevation separation (passes through as-is)
geoPosition.elevation_diff = 40;
newPosition = passThroughTransformer.processBluetoothPosition( geoPosition );
newPosition = disabledTransformer.processBluetoothPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
QVERIFY( qgsDoubleNear( newPosition.longitude, 17.1064 ) );
QCOMPARE( newPosition.elevation, 171.3 );
QCOMPARE( newPosition.elevation_diff, 40 );

// transform with pass through disabled and elevation separation
// transform with transformation enabled and elevation separation
newPosition = positionTransformer.processBluetoothPosition( geoPosition );

QVERIFY( qgsDoubleNear( newPosition.latitude, 48.10305 ) );
Expand Down Expand Up @@ -657,8 +657,8 @@ void TestPosition::testPositionTransformerInternalIosPosition()
QgsCoordinateReferenceSystem ellipsoidHeightCrs = QgsCoordinateReferenceSystem::fromEpsgId( 4979 );
// WGS84 + EGM96
QgsCoordinateReferenceSystem geoidHeightCrs = QgsCoordinateReferenceSystem::fromEpsgId( 9707 );
PositionTransformer positionTransformer( ellipsoidHeightCrs, geoidHeightCrs, false, QgsCoordinateTransformContext() );
PositionTransformer passThroughTransformer( ellipsoidHeightCrs, geoidHeightCrs, true, QgsCoordinateTransformContext() );
PositionTransformer positionTransformer( ellipsoidHeightCrs, geoidHeightCrs, true, QgsCoordinateTransformContext() );
PositionTransformer disabledTransformer( ellipsoidHeightCrs, geoidHeightCrs, false, QgsCoordinateTransformContext() );

#ifdef HAVE_BLUETOOTH
// mini file contains only minimal info like position and date
Expand Down Expand Up @@ -704,7 +704,7 @@ void TestPosition::testPositionTransformerInternalIosPosition()

// mocked
geoPosition.setAttribute( QGeoPositionInfo::MagneticVariation, 1 );
// transform with pass through disabled, position is mocked and orthometric
// transform with transformation enabled, position is mocked and orthometric
newPosition = positionTransformer.processInternalIosPosition( geoPosition );

QCOMPARE( newPosition.elevation, 127.53574931171875 );
Expand All @@ -717,8 +717,8 @@ void TestPosition::testPositionTransformerInternalIosPosition()
geoPosition.setAttribute( QGeoPositionInfo::VerticalSpeed, 1 );
// mocked
geoPosition.setAttribute( QGeoPositionInfo::MagneticVariation, 1 );
// transform with pass through enabled, position is mocked and ellipsoid
newPosition = passThroughTransformer.processInternalIosPosition( geoPosition );
// transform with transformation disabled, position is mocked and ellipsoid (passed through as-is)
newPosition = disabledTransformer.processInternalIosPosition( geoPosition );

QCOMPARE( newPosition.elevation, 171.3 );
QCOMPARE( newPosition.elevation_diff, std::numeric_limits<double>::quiet_NaN() );
Expand Down
Loading