diff --git a/app/main.cpp b/app/main.cpp index e91cb18ec..60ce2393c 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -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() ); } ); diff --git a/app/position/positionkit.cpp b/app/position/positionkit.cpp index 85c6677a5..5ee0ca149 100644 --- a/app/position/positionkit.cpp +++ b/app/position/positionkit.cpp @@ -31,12 +31,12 @@ PositionKit::PositionKit( QObject *parent ) : QObject( parent ) { - mPositionTransformer = std::make_unique( positionCrs3DEllipsoidHeight(), positionCrs3D(), mSkipElevationTransformation, QgsCoordinateTransformContext() ); + mPositionTransformer = std::make_unique( positionCrs3DEllipsoidHeight(), positionCrs3D(), mElevationTransformationEnabled, QgsCoordinateTransformContext() ); } QgsCoordinateReferenceSystem PositionKit::positionCrs3D() { - if ( !mSkipElevationTransformation && mPositionCrs3D.isValid() ) + if ( mElevationTransformationEnabled && mPositionCrs3D.isValid() ) { return mPositionCrs3D; } @@ -45,7 +45,7 @@ QgsCoordinateReferenceSystem PositionKit::positionCrs3D() QString PositionKit::positionCrs3DGeoidModelName() { - if ( !mSkipElevationTransformation ) + if ( mElevationTransformationEnabled ) { return mVerticalCrs.description(); } @@ -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 ) @@ -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 ); } diff --git a/app/position/positionkit.h b/app/position/positionkit.h index b0ab11de9..35b42f530 100644 --- a/app/position/positionkit.h +++ b/app/position/positionkit.h @@ -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 ); @@ -201,7 +201,7 @@ class PositionKit : public QObject QgsCoordinateReferenceSystem mPositionCrs3D; QgsCoordinateReferenceSystem mVerticalCrs; - bool mSkipElevationTransformation = true; + bool mElevationTransformationEnabled = false; friend class TestPosition; }; diff --git a/app/position/positiontransformer.cpp b/app/position/positiontransformer.cpp index 3d5dd559c..59af33c34 100644 --- a/app/position/positiontransformer.cpp +++ b/app/position/positiontransformer.cpp @@ -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 @@ -55,7 +55,7 @@ GeoPosition PositionTransformer::processAndroidPosition( GeoPosition geoPosition if ( geoPosition.elevation != std::numeric_limits::quiet_NaN() ) { bool positionOutsideGeoidModelArea = false; - if ( !geoPosition.isMock || !mSkipElevationTransformation ) + if ( !geoPosition.isMock || mElevationTransformationEnabled ) { const QgsPoint geoidPosition = InputUtils::transformPoint( mSourceCrs, @@ -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 ); @@ -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, @@ -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(); @@ -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; } diff --git a/app/position/positiontransformer.h b/app/position/positiontransformer.h index 87e4a2c6a..dbb6841ea 100644 --- a/app/position/positiontransformer.h +++ b/app/position/positiontransformer.h @@ -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. */ @@ -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. @@ -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; }; diff --git a/app/test/testposition.cpp b/app/test/testposition.cpp index 6c0bdba26..b64e0e45d 100644 --- a/app/test/testposition.cpp +++ b/app/test/testposition.cpp @@ -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 @@ -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::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 ) ); @@ -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 @@ -581,7 +581,7 @@ 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 ) ); @@ -589,24 +589,24 @@ void TestPosition::testPositionTransformerBluetoothPosition() QCOMPARE( newPosition.elevation, 171.3 ); QCOMPARE( newPosition.elevation_diff, std::numeric_limits::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::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 ) ); @@ -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 @@ -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 ); @@ -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::quiet_NaN() );