@@ -420,9 +420,12 @@ Observer::Observer(const Observer& o) :
420420 position(o.position),
421421 originalOrientation(o.originalOrientation),
422422 transformedOrientation(o.transformedOrientation),
423- orientationTransform(o.orientationTransform),
423+ devicePoseQuaternion(o.devicePoseQuaternion),
424+ eulerDrivenOrientation(o.eulerDrivenOrientation),
425+ inputEulerAngles(o.inputEulerAngles),
424426 velocity(o.velocity),
425427 angularVelocity(o.angularVelocity),
428+ inputAngularVelocity(o.inputAngularVelocity),
426429 realTime(o.realTime),
427430 targetSpeed(o.targetSpeed),
428431 targetVelocity(o.targetVelocity),
@@ -447,10 +450,13 @@ Observer& Observer::operator=(const Observer& o)
447450 simTime = o.simTime ;
448451 position = o.position ;
449452 originalOrientation = o.originalOrientation ;
450- orientationTransform = o.orientationTransform ;
453+ devicePoseQuaternion = o.devicePoseQuaternion ;
454+ eulerDrivenOrientation = o.eulerDrivenOrientation ;
455+ inputEulerAngles = o.inputEulerAngles ;
451456 transformedOrientation = o.transformedOrientation ;
452457 velocity = o.velocity ;
453458 angularVelocity = o.angularVelocity ;
459+ inputAngularVelocity = o.inputAngularVelocity ;
454460 frame = nullptr ;
455461 realTime = o.realTime ;
456462 targetSpeed = o.targetSpeed ;
@@ -581,13 +587,13 @@ Observer::setOriginalOrientation(const Eigen::Quaterniond& q)
581587const Eigen::Quaterniond&
582588Observer::getOrientationTransform () const
583589{
584- return orientationTransform ;
590+ return devicePoseQuaternion ;
585591}
586592
587593void
588594Observer::setOrientationTransform (const Eigen::Quaterniond& transform)
589595{
590- orientationTransform = transform;
596+ devicePoseQuaternion = transform;
591597 updateOrientation ();
592598}
593599
@@ -598,7 +604,9 @@ Observer::applyCurrentTransform()
598604{
599605 originalOrientationUniv = transformedOrientationUniv;
600606 originalOrientation = transformedOrientation;
601- orientationTransform = Eigen::Quaterniond::Identity ();
607+ devicePoseQuaternion = Eigen::Quaterniond::Identity ();
608+ inputEulerAngles = Eigen::Vector3d::Identity ();
609+ eulerDrivenOrientation = Eigen::Quaterniond::Identity ();
602610 updateOrientation ();
603611}
604612
@@ -630,6 +638,18 @@ Observer::setAngularVelocity(const Eigen::Vector3d& v)
630638 angularVelocity = v;
631639}
632640
641+ Eigen::Vector3d
642+ Observer::getInputAngularVelocity () const
643+ {
644+ return inputAngularVelocity;
645+ }
646+
647+ void
648+ Observer::setInputAngularVelocity (const Eigen::Vector3d& v)
649+ {
650+ inputAngularVelocity = v;
651+ }
652+
633653double
634654Observer::getArrivalTime () const
635655{
@@ -687,7 +707,7 @@ Observer::update(double dt, double timeScale)
687707
688708 // At some threshold, we just set the velocity to zero; otherwise,
689709 // we'll end up with ridiculous velocities like 10^-40 m/s.
690- if (v.norm () < 1.0e-12 )
710+ if (v.norm () < celestia::engine::MIN_SIG_LINEAR_SPEED )
691711 v = Eigen::Vector3d::Zero ();
692712 setVelocity (v);
693713 }
@@ -702,6 +722,19 @@ Observer::update(double dt, double timeScale)
702722 Eigen::Quaterniond dr = Eigen::Quaterniond (0.0 , halfAV.x (), halfAV.y (), halfAV.z ()) * transformedOrientation;
703723 Eigen::Quaterniond expectedOrientation = Eigen::Quaterniond (transformedOrientation.coeffs () + dt * dr.coeffs ()).normalized ();
704724 originalOrientation = undoTransform (expectedOrientation);
725+
726+ // Update the input angular orientation transform
727+ if (inputAngularVelocity.norm () > celestia::engine::MIN_SIG_ANGULAR_SPEED)
728+ {
729+ inputEulerAngles += inputAngularVelocity * dt;
730+ // Clamp pitch between -90 and +90 to avoid gimbal lock
731+ inputEulerAngles[0 ] = std::clamp (std::remainder (inputEulerAngles[0 ], 2 * celestia::numbers::pi), -0.5 * celestia::numbers::pi + std::numeric_limits<double >::epsilon (), 0.5 * celestia::numbers::pi - std::numeric_limits<double >::epsilon ());
732+ inputEulerAngles[1 ] = std::remainder (inputEulerAngles[1 ], 2 * celestia::numbers::pi);
733+ inputEulerAngles[2 ] = std::remainder (inputEulerAngles[2 ], 2 * celestia::numbers::pi);
734+ eulerDrivenOrientation = Eigen::AngleAxisd (inputEulerAngles[0 ], Eigen::Vector3d::UnitX ()) *
735+ Eigen::AngleAxisd (inputEulerAngles[1 ], Eigen::Vector3d::UnitY ()) *
736+ Eigen::AngleAxisd (inputEulerAngles[2 ], Eigen::Vector3d::UnitZ ());
737+ }
705738 }
706739
707740 updateUniversal ();
@@ -720,14 +753,14 @@ Observer::update(double dt, double timeScale)
720753void
721754Observer::updateOrientation ()
722755{
723- transformedOrientationUniv = orientationTransform * originalOrientationUniv;
756+ transformedOrientationUniv = eulerDrivenOrientation * devicePoseQuaternion * originalOrientationUniv;
724757 transformedOrientation = frame->convertFromUniversal (transformedOrientationUniv, getTime ());
725758}
726759
727760Eigen::Quaterniond
728761Observer::undoTransform (const Eigen::Quaterniond& transformed) const
729762{
730- return orientationTransform .inverse () * transformed;
763+ return devicePoseQuaternion .inverse () * eulerDrivenOrientation. inverse () * transformed;
731764}
732765
733766Selection
@@ -1246,7 +1279,7 @@ Observer::gotoJourney(const JourneyParams& params)
12461279void
12471280Observer::startTraveling ()
12481281{
1249- journey.orientationTransformInverse = orientationTransform .inverse ();
1282+ journey.orientationTransformInverse = devicePoseQuaternion. inverse () * eulerDrivenOrientation .inverse ();
12501283 observerMode = ObserverMode::Travelling;
12511284}
12521285
0 commit comments