Files
OpenVR-AdvancedSettings-frame/src/tabcontrollers/RotationTabController.cpp
T
2025-10-09 18:45:53 -05:00

808 lines
31 KiB
C++

#include "RotationTabController.h"
#include <QQuickWindow>
#include <QtLogging>
#include <QtDebug>
#include "../overlaycontroller.h"
#include "../settings/settings.h"
#include "../utils/Matrix.h"
#include "../quaternion/quaternion.h"
#include <cmath>
// application namespace
namespace advsettings
{
void RotationTabController::initStage1()
{ // TODO adjust update rate
// m_chaperoneSettingsUpdateCounter
// = utils::adjustUpdateRate( k_chaperoneSettingsUpdateCounter );
}
void RotationTabController::initStage2( OverlayController* var_parent )
{
this->parent = var_parent;
const auto autoturnOverlayKey
= std::string( application_strings::applicationKey )
+ ".autoturnnotification";
const auto overlayError
= vr::VROverlay()->CreateOverlay( autoturnOverlayKey.c_str(),
autoturnOverlayKey.c_str(),
&m_autoturnValues.overlayHandle );
if ( overlayError != vr::VROverlayError_None )
{
qCritical() << "Could not create autoturn notification overlay: "
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
overlayError );
emit defaultProfileDisplay();
return;
}
m_autoturnValues.autoturnImg.reset(
new QImage( ":qt/qml/AdvancedSettings/src/res/img/rotation/autoturn.png" ) );
m_autoturnValues.noautoturnImg.reset(
new QImage( ":qt/qml/AdvancedSettings/src/res/img/rotation/noautoturn.png" ) );
ovr_overlay_wrapper::setOverlayFromQImage( m_autoturnValues.overlayHandle,
*m_autoturnValues.autoturnImg );
vr::VROverlay()->SetOverlayWidthInMeters( m_autoturnValues.overlayHandle,
0.02f );
vr::HmdMatrix34_t notificationTransform
= { { { 1.0f, 0.0f, 0.0f, 0.12f },
{ 0.0f, 1.0f, 0.0f, 0.08f },
{ 0.0f, 0.0f, 1.0f, -0.3f } } };
vr::VROverlay()->SetOverlayTransformTrackedDeviceRelative(
m_autoturnValues.overlayHandle,
vr::k_unTrackedDeviceIndex_Hmd,
&notificationTransform );
emit defaultProfileDisplay();
}
void RotationTabController::eventLoopTick(
vr::TrackedDevicePose_t* devicePoses )
{
if ( devicePoses )
{
m_isHMDActive = false;
std::lock_guard<std::recursive_mutex> lock(
parent->chaperoneUtils().mutex() );
auto& poseHmd = devicePoses[vr::k_unTrackedDeviceIndex_Hmd];
// m_isHMDActive is true when prox sensor OR HMD is moving (~10 seconds
// to update from OVR)
// THIS IS A WORK-AROUND Until proper binding support/calls are made
// availble for prox sensor
if ( vr::VRSystem()->GetTrackedDeviceActivityLevel(
vr::k_unTrackedDeviceIndex_Hmd )
== vr::k_EDeviceActivityLevel_UserInteraction )
{
m_isHMDActive = true;
}
if ( poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK )
{
auto chaperoneDistances
= parent->chaperoneUtils().getDistancesToChaperone(
{ poseHmd.mDeviceToAbsoluteTracking.m[0][3],
poseHmd.mDeviceToAbsoluteTracking.m[1][3],
poseHmd.mDeviceToAbsoluteTracking.m[2][3] } );
// Autoturn mode
if ( RotationTabController::autoTurnEnabled() )
{
doAutoTurn( poseHmd, chaperoneDistances );
}
// Vestibular motion. Dependent on autoTurn so the playspace
// doesn't move when you use the keybind
if ( RotationTabController::vestibularMotionEnabled() )
{
doVestibularMotion( poseHmd, chaperoneDistances );
}
if ( RotationTabController::viewRatchettingEnabled() )
{
doViewRatchetting( poseHmd, chaperoneDistances );
}
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
m_autoTurnChaperoneDistancesLast = std::move( chaperoneDistances );
}
}
if ( m_autoTurnNotificationTimestamp )
{
auto count = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now()
- *m_autoTurnNotificationTimestamp )
.count();
if ( count > 1500 )
{
m_autoTurnNotificationTimestamp.reset();
if ( getNotificationOverlayHandle()
!= vr::k_ulOverlayHandleInvalid )
{
vr::VROverlay()->HideOverlay( getNotificationOverlayHandle() );
}
}
else
{
float pct
= std::min( 1.0f, 3.0f - static_cast<float>( count ) / 500.0f );
vr::VROverlay()->SetOverlayAlpha( getNotificationOverlayHandle(),
pct );
}
}
}
void RotationTabController::doViewRatchetting(
const vr::TrackedDevicePose_t& poseHmd,
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances )
{
if ( m_isHMDActive && poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK
&& !chaperoneDistances.empty() )
{
if ( chaperoneDistances.size()
!= m_autoTurnChaperoneDistancesLast.size() )
{
m_autoTurnChaperoneDistancesLast = chaperoneDistances;
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
}
// Find the (index of the) nearest wall
size_t nearestWallIdx = 0;
for ( size_t i = 0; i < chaperoneDistances.size(); i++ )
{
if ( chaperoneDistances[i].distance
< chaperoneDistances[nearestWallIdx].distance )
{
nearestWallIdx = i;
}
}
const auto& nearestWall = chaperoneDistances[nearestWallIdx];
// Convert pose matrix to quaternion
auto hmdQuaternion
= quaternion::fromHmdMatrix34( poseHmd.mDeviceToAbsoluteTracking );
// Get HMD raw yaw
double hmdYaw = quaternion::getYaw( hmdQuaternion );
// Get angle between HMD position and nearest point on
// wall
double hmdPositionToWallYaw = static_cast<double>(
std::atan2( nearestWall.nearestPoint.v[0]
- poseHmd.mDeviceToAbsoluteTracking.m[0][3],
nearestWall.nearestPoint.v[2]
- poseHmd.mDeviceToAbsoluteTracking.m[2][3] ) );
// Get angle between HMD and wall
double hmdToWallYaw
= reduceAngle<>( hmdYaw - hmdPositionToWallYaw, -M_PI, M_PI );
do
{
// if we change walls, ignore
if ( nearestWallIdx != m_ratchettingLastWall )
{
break;
}
// Facing away from the wall is 0, |facing towards the wall| is M_PI
// Ignore turning towards the wall (e.g. change in magnitude is
// greater than 0)
if ( std::abs( hmdToWallYaw )
- std::abs( m_ratchettingLastHmdRotation )
> 0.0 )
{
break;
}
// Magnify that change
double delta_degrees
= reduceAngle<>(
hmdToWallYaw - m_ratchettingLastHmdRotation, -M_PI, M_PI )
* viewRatchettingPercent();
parent->m_moveCenterTabController.setRotation(
parent->m_moveCenterTabController.rotation()
+ static_cast<int>( delta_degrees * k_radiansToCentidegrees ) );
} while ( false );
m_ratchettingLastHmdRotation = hmdToWallYaw;
m_ratchettingLastWall = nearestWallIdx;
}
}
void RotationTabController::doVestibularMotion(
const vr::TrackedDevicePose_t& poseHmd,
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances )
{
if ( m_isHMDActive && poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK
&& !chaperoneDistances.empty() )
{
if ( chaperoneDistances.size()
!= m_autoTurnChaperoneDistancesLast.size() )
{
m_autoTurnChaperoneDistancesLast = chaperoneDistances;
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
}
// Rotate dist/(2*pi*r) where r is
// m_autoTurnVestibularMotionRadius, as if we had walked
// however many inches along a circle and the world was
// turning to compensate
do
{
// Find the nearest wall
const auto& nearestWall
= std::min_element( chaperoneDistances.begin(),
chaperoneDistances.end(),
[]( const auto& quadA, const auto& quadB ) {
return quadA.distance < quadB.distance;
} );
// Convert pose matrix to quaternion
auto hmdQuaternion = quaternion::fromHmdMatrix34(
poseHmd.mDeviceToAbsoluteTracking );
// Get HMD raw yaw
double hmdYaw = quaternion::getYaw( hmdQuaternion );
// Get angle between HMD position and nearest point on
// wall
double hmdPositionToWallYaw = static_cast<double>(
std::atan2( poseHmd.mDeviceToAbsoluteTracking.m[0][3]
- nearestWall->nearestPoint.v[0],
poseHmd.mDeviceToAbsoluteTracking.m[2][3]
- nearestWall->nearestPoint.v[2] ) );
// Get angle between HMD and wall
double hmdToWallYaw
= reduceAngle<>( hmdYaw - hmdPositionToWallYaw, -M_PI, M_PI );
bool turnLeft = hmdToWallYaw > 0.0;
// Only turn if moving forward
double hmdMovementDirection = static_cast<double>(
std::atan2( m_autoTurnLastHmdUpdate.m[0][3]
- poseHmd.mDeviceToAbsoluteTracking.m[0][3],
m_autoTurnLastHmdUpdate.m[2][3]
- poseHmd.mDeviceToAbsoluteTracking.m[2][3] ) );
if ( std::abs( hmdYaw - hmdMovementDirection )
* k_radiansToCentidegrees
>= 7000 )
{
break;
}
// Get the distance between previous and current
// position
double distanceChange = static_cast<double>(
std::hypot( poseHmd.mDeviceToAbsoluteTracking.m[0][3]
- m_autoTurnLastHmdUpdate.m[0][3],
poseHmd.mDeviceToAbsoluteTracking.m[2][3]
- m_autoTurnLastHmdUpdate.m[2][3] ) );
// Get the arc length between the previous point and current point
// 2 sin-1( (d/2)/r ) (in radians)
double arcLength = 2
* std::asin( ( distanceChange / 2 )
/ vestibularMotionRadius() );
if ( std::isnan( arcLength ) )
{
break;
}
double rotationAmount = arcLength * ( turnLeft ? 1 : -1 );
int newRotationAngle = reduceAngle<>(
parent->m_moveCenterTabController.rotation()
+ static_cast<int>( rotationAmount
* k_radiansToCentidegrees ),
0,
36000 );
parent->m_moveCenterTabController.setRotation( newRotationAngle );
} while ( false );
}
}
void RotationTabController::doAutoTurn(
const vr::TrackedDevicePose_t& poseHmd,
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances )
{
if ( m_isHMDActive && poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK
&& !chaperoneDistances.empty() )
{
auto currentTime = std::chrono::steady_clock::now();
if ( m_autoTurnWallActive.size() != chaperoneDistances.size() )
{
// Chaperone changed
m_autoTurnWallActive.clear();
// Initialize all to 'true' so we don't rotate on startup if
// the user is outside of the play area.
m_autoTurnWallActive.resize( chaperoneDistances.size(), true );
m_autoTurnLastUpdate = currentTime;
}
// Apply smooth rotation per-frame: get the time since last frame,
// multiply by speed
if ( RotationTabController::autoTurnModeType()
== AutoTurnModes::LINEAR_SMOOTH_TURN
&& m_autoTurnLinearSmoothTurnRemaining != 0 )
{
double deltaSeconds
= FrameRates::toDoubleSeconds( m_estimatedFrameRate );
auto miniDeltaAngle = static_cast<int>(
std::abs(
( deltaSeconds * RotationTabController::autoTurnSpeed() ) )
* ( m_autoTurnLinearSmoothTurnRemaining < 0 ? -1 : 1 ) );
if ( std::abs( m_autoTurnLinearSmoothTurnRemaining )
< std::abs( miniDeltaAngle ) )
{
miniDeltaAngle = m_autoTurnLinearSmoothTurnRemaining;
}
int newRotationAngleDeg
= reduceAngle<>( parent->m_moveCenterTabController.rotation()
+ static_cast<int>( miniDeltaAngle ),
0,
36000 );
parent->m_moveCenterTabController.setRotation(
newRotationAngleDeg );
m_autoTurnLinearSmoothTurnRemaining -= miniDeltaAngle;
}
for ( size_t i = 0; i < chaperoneDistances.size(); i++ )
{
const auto& chaperoneQuad = chaperoneDistances[i];
if ( chaperoneQuad.distance
<= RotationTabController::autoTurnActivationDistance()
&& !m_autoTurnWallActive[i] )
{
// Convert pose matrix to quaternion
auto hmdQuaternion = quaternion::fromHmdMatrix34(
poseHmd.mDeviceToAbsoluteTracking );
// Get HMD raw yaw
double hmdYaw = quaternion::getYaw( hmdQuaternion );
// Get angle between HMD position and nearest point on
// wall
double hmdPositionToWallYaw = static_cast<double>(
std::atan2( poseHmd.mDeviceToAbsoluteTracking.m[0][3]
- chaperoneQuad.nearestPoint.v[0],
poseHmd.mDeviceToAbsoluteTracking.m[2][3]
- chaperoneQuad.nearestPoint.v[2] ) );
// Get angle between HMD and wall
double hmdToWallYaw = reduceAngle<>(
hmdYaw - hmdPositionToWallYaw, -M_PI, M_PI );
do
{
// Ignore if the wall we encountered is behind us
if ( std::abs( hmdToWallYaw ) >= M_PI / 2 )
{
qDebug() << "Ignoring turn in opposite "
"direction (angle "
<< std::abs( hmdToWallYaw ) << ")";
break;
}
// If the closest corner shares a wall with the last
// wall we turned at, turn relative to that corner
bool cornerShared
= m_autoTurnWallActive[circularIndex(
i, true, chaperoneDistances.size() )]
|| m_autoTurnWallActive[circularIndex(
i, false, chaperoneDistances.size() )];
bool turnLeft = true;
// Turn away from corner
if ( cornerShared )
{
// Turn left or right depending on which corner
// it is. If we go based on yaw, we could end up
// turning the wrong way if it's large obtuse
// angle and we're facing more towards the
// previous wall than the left.
turnLeft = m_autoTurnWallActive[circularIndex(
i, false, chaperoneDistances.size() )];
qDebug() << "turning away from shared corner";
}
// If within m_cordDetanglingAngle degrees of
// 'straight at a wall', start in whatever direction
// will start untangling your cord
else if ( ( std::abs( hmdToWallYaw )
<= RotationTabController::cordDetangleAngle() )
&& ( std::abs( parent->m_moveCenterTabController
.getHmdYawTotal() )
> RotationTabController::minCordTangle() ) )
{
turnLeft = ( parent->m_moveCenterTabController
.getHmdYawTotal()
< 0.0 );
qDebug() << "turning to detangle cord";
}
// Turn the closest angle to the wall
else
{
turnLeft = hmdToWallYaw > 0.0;
qDebug() << "turning closest angle to wall";
}
qDebug() << "hmd yaw " << hmdYaw
<< ", hmd position to wall angle "
<< hmdPositionToWallYaw;
qDebug() << "hmd to wall angle " << hmdToWallYaw;
// Positive hmd-to-wall is facing left, negative is
// facing right (relative to the wall)
double delta_degrees
= ( ( turnLeft ? M_PI / 2 : -M_PI / 2 ) - hmdToWallYaw )
* k_radiansToCentidegrees;
if ( RotationTabController::autoTurnUseCornerAngle()
&& cornerShared )
{
// Turn the angle of the corner
// Three relevant points - the far corner wall
// we're currently touching, the far corner on
// the wall we've just touched, and the corner
// between them
const size_t cornerCnt
= parent->chaperoneUtils().quadsCount();
const size_t middleCornerIdx
= turnLeft ? i
: circularIndex( i, true, cornerCnt );
const auto& middleCorner
= parent->chaperoneUtils().getCorner(
middleCornerIdx );
const auto& newWallCorner
= parent->chaperoneUtils().getCorner( circularIndex(
middleCornerIdx, turnLeft, cornerCnt ) );
const auto& touchingWallCorner
= parent->chaperoneUtils().getCorner( circularIndex(
middleCornerIdx, !turnLeft, cornerCnt ) );
double newWallAngle = static_cast<double>( std::atan2(
middleCorner.v[0] - newWallCorner.v[0],
middleCorner.v[2] - newWallCorner.v[2] ) );
double touchingWallAngle
= static_cast<double>( std::atan2(
middleCorner.v[0] - touchingWallCorner.v[0],
middleCorner.v[2] - touchingWallCorner.v[2] ) );
qDebug() << "twa: " << touchingWallAngle
<< ", nwa: " << newWallAngle << ", diff: "
<< ( newWallAngle - touchingWallAngle );
delta_degrees = ( newWallAngle - touchingWallAngle
+ ( turnLeft ? M_PI : -M_PI ) )
* k_radiansToCentidegrees;
delta_degrees
= reduceAngle<>( delta_degrees, -18000.0, 18000.0 );
}
qDebug() << "rotating space " << ( delta_degrees / 100 )
<< " degrees";
switch ( RotationTabController::autoTurnModeType() )
{
case AutoTurnModes::SNAP:
parent->m_moveCenterTabController.setRotation(
parent->m_moveCenterTabController.rotation()
+ static_cast<int>( delta_degrees ) );
break;
case AutoTurnModes::LINEAR_SMOOTH_TURN:
m_autoTurnLinearSmoothTurnRemaining
+= static_cast<int>( delta_degrees );
break;
}
} while ( false );
m_autoTurnWallActive[i] = true;
auto delta = currentTime - m_autoTurnLastUpdate;
if ( delta
< ( FrameRates::RATE_144HZ + FrameRates::RATE_120HZ ) / 2 )
{
m_estimatedFrameRate = FrameRates::RATE_144HZ;
}
else if ( ( delta >= ( FrameRates::RATE_144HZ
+ FrameRates::RATE_120HZ )
/ 2 )
&& ( delta < ( FrameRates::RATE_120HZ
+ FrameRates::RATE_90HZ )
/ 2 ) )
{
m_estimatedFrameRate = FrameRates::RATE_120HZ;
}
else if ( ( delta >= ( FrameRates::RATE_120HZ
+ FrameRates::RATE_90HZ )
/ 2 )
&& ( delta < ( FrameRates::RATE_90HZ
+ FrameRates::RATE_72HZ )
/ 2 ) )
{
m_estimatedFrameRate = FrameRates::RATE_90HZ;
}
else if ( ( delta
>= ( FrameRates::RATE_90HZ + FrameRates::RATE_72HZ )
/ 2 )
&& ( delta < ( FrameRates::RATE_72HZ
+ FrameRates::RATE_60HZ )
/ 2 ) )
{
m_estimatedFrameRate = FrameRates::RATE_72HZ;
}
else if ( ( delta
>= ( FrameRates::RATE_72HZ + FrameRates::RATE_60HZ )
/ 2 )
&& ( delta < ( FrameRates::RATE_60HZ
+ FrameRates::RATE_45HZ )
/ 2 ) )
{
m_estimatedFrameRate = FrameRates::RATE_60HZ;
}
else
{
m_estimatedFrameRate = FrameRates::RATE_45HZ;
}
}
else if ( ( chaperoneQuad.distance
> ( RotationTabController::autoTurnActivationDistance()
+ RotationTabController::
autoTurnDeactivationDistance() ) )
&& m_autoTurnWallActive[i] )
{
m_autoTurnWallActive[i] = false;
}
}
m_autoTurnLastUpdate = currentTime;
}
else
{
m_autoTurnWallActive.clear();
}
}
// getters
bool RotationTabController::autoTurnEnabled() const
{
return settings::getSetting(
settings::BoolSetting::ROTATION_autoturnEnabled );
}
float RotationTabController::autoTurnActivationDistance() const
{
return static_cast<float>( settings::getSetting(
settings::DoubleSetting::ROTATION_activationDistance ) );
}
float RotationTabController::autoTurnDeactivationDistance() const
{
return static_cast<float>( settings::getSetting(
settings::DoubleSetting::ROTATION_deactivateDistance ) );
}
bool RotationTabController::autoTurnUseCornerAngle() const
{
return settings::getSetting(
settings::BoolSetting::ROTATION_autoturnUseCornerAngle );
}
bool RotationTabController::autoTurnShowNotification() const
{
return settings::getSetting(
settings::BoolSetting::ROTATION_autoturnShowNotification );
}
double RotationTabController::cordDetangleAngle() const
{
return settings::getSetting(
settings::DoubleSetting::ROTATION_cordDetanglingAngle );
}
double RotationTabController::minCordTangle() const
{
return settings::getSetting(
settings::DoubleSetting::ROTATION_autoturnMinCordTangle );
}
int RotationTabController::autoTurnSpeed() const
{
return settings::getSetting(
settings::IntSetting::ROTATION_autoturnLinearTurnSpeed );
}
AutoTurnModes RotationTabController::autoTurnModeType() const
{
return static_cast<AutoTurnModes>(
settings::getSetting( settings::IntSetting::ROTATION_autoturnMode ) );
}
int RotationTabController::autoTurnMode() const
{
return settings::getSetting( settings::IntSetting::ROTATION_autoturnMode );
}
bool RotationTabController::vestibularMotionEnabled() const
{
return settings::getSetting(
settings::BoolSetting::ROTATION_autoturnVestibularMotionEnabled );
}
double RotationTabController::vestibularMotionRadius() const
{
return settings::getSetting(
settings::DoubleSetting::ROTATION_autoturnVestibularMotionRadius );
}
bool RotationTabController::viewRatchettingEnabled() const
{
return settings::getSetting(
settings::BoolSetting::ROTATION_autoturnViewRatchettingEnabled );
}
double RotationTabController::viewRatchettingPercent() const
{
return settings::getSetting(
settings::DoubleSetting::ROTATION_autoturnViewRatchettingPercent );
}
// Setters
void RotationTabController::setAutoTurnEnabled( bool value, bool notify )
{
settings::setSetting( settings::BoolSetting::ROTATION_autoturnEnabled,
value );
if ( notify )
{
emit autoTurnEnabledChanged( value );
}
if ( autoTurnShowNotification()
&& getNotificationOverlayHandle() != vr::k_ulOverlayHandleInvalid )
{
if ( !value )
{
ovr_overlay_wrapper::setOverlayFromQImage(
m_autoturnValues.overlayHandle,
*m_autoturnValues.noautoturnImg );
}
else
{
ovr_overlay_wrapper::setOverlayFromQImage(
m_autoturnValues.overlayHandle, *m_autoturnValues.autoturnImg );
}
vr::VROverlay()->SetOverlayAlpha( getNotificationOverlayHandle(),
1.0f );
vr::VROverlay()->ShowOverlay( getNotificationOverlayHandle() );
m_autoTurnNotificationTimestamp.emplace(
std::chrono::steady_clock::now() );
}
}
void RotationTabController::setAutoTurnShowNotification( bool value,
bool notify )
{
settings::setSetting(
settings::BoolSetting::ROTATION_autoturnShowNotification, value );
if ( notify )
{
emit autoTurnShowNotificationChanged( value );
}
}
void RotationTabController::setAutoTurnActivationDistance( float value,
bool notify )
{
settings::setSetting( settings::DoubleSetting::ROTATION_activationDistance,
static_cast<double>( value ) );
if ( notify )
{
emit autoTurnActivationDistanceChanged( value );
}
}
void RotationTabController::setAutoTurnDeactivationDistance( float value,
bool notify )
{
settings::setSetting( settings::DoubleSetting::ROTATION_deactivateDistance,
static_cast<double>( value ) );
if ( notify )
{
emit autoTurnDeactivationDistanceChanged( value );
}
}
void RotationTabController::setAutoTurnUseCornerAngle( bool value, bool notify )
{
settings::setSetting(
settings::BoolSetting::ROTATION_autoturnUseCornerAngle, value );
if ( notify )
{
emit autoTurnUseCornerAngleChanged( value );
}
}
void RotationTabController::setCordDetangleAngle( double value, bool notify )
{
settings::setSetting( settings::DoubleSetting::ROTATION_cordDetanglingAngle,
value );
if ( notify )
{
emit cordDetangleAngleChanged( value );
}
}
void RotationTabController::setMinCordTangle( double value, bool notify )
{
settings::setSetting(
settings::DoubleSetting::ROTATION_autoturnMinCordTangle, value );
if ( notify )
{
emit minCordTangleChanged( value );
}
}
void RotationTabController::setAutoTurnSpeed( int value, bool notify )
{
settings::setSetting(
settings::IntSetting::ROTATION_autoturnLinearTurnSpeed, value );
if ( notify )
{
emit autoTurnSpeedChanged( value );
}
}
void RotationTabController::setAutoTurnMode( int value, bool notify )
{
settings::setSetting( settings::IntSetting::ROTATION_autoturnMode, value );
if ( notify )
{
emit autoTurnModeChanged( value );
}
}
void RotationTabController::setVestibularMotionEnabled( bool value,
bool notify )
{
settings::setSetting(
settings::BoolSetting::ROTATION_autoturnVestibularMotionEnabled,
value );
if ( notify )
{
emit vestibularMotionEnabledChanged( value );
}
}
void RotationTabController::setVestibularMotionRadius( double value,
bool notify )
{
settings::setSetting(
settings::DoubleSetting::ROTATION_autoturnVestibularMotionRadius,
value );
if ( notify )
{
emit vestibularMotionRadiusChanged( value );
}
}
void RotationTabController::setViewRatchettingEnabled( bool value, bool notify )
{
settings::setSetting(
settings::BoolSetting::ROTATION_autoturnViewRatchettingEnabled, value );
if ( notify )
{
emit viewRatchettingEnabledChanged( value );
}
}
void RotationTabController::setViewRatchettingPercent( double value,
bool notify )
{
settings::setSetting(
settings::DoubleSetting::ROTATION_autoturnViewRatchettingPercent,
value );
if ( notify )
{
emit viewRatchettingPercentChanged( value );
}
}
} // namespace advsettings