From 5605b49907ad7e5c84c08ce416941f92f418c7db Mon Sep 17 00:00:00 2001
From: Austin Sanders <arsanders@usgs.gov>
Date: Fri, 15 Nov 2024 11:22:56 -0700
Subject: [PATCH] Update quaternions to prevent sign flipping (#623)

* Updated quaternion accessor to prevent unwanted sign flip

* Updated changelog

* flipped quaternion signs to follow new logic

---------

Co-authored-by: Sanders <arsanders@igswza281l2314.gs.doi.net>
---
 CHANGELOG.md                             |  1 +
 ale/rotation.py                          | 22 +++++++++++++++++++++-
 tests/pytests/data/isds/dawnvir_isd.json |  8 ++++----
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58a7bf4..dc3d7d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -58,6 +58,7 @@ release.
 - Fixed incorrect distortion look up in Orex camera when working with PolyCam images [#583](https://github.com/DOI-USGS/ale/pull/583)
 - Brought timing in line with ISIS for the KaguyaMiIsisLabelNaifSpiceDriver [#599](https://github.com/DOI-USGS/ale/pull/599)
 - Brought timing in line with ISIS for the MroMarciIsisLabelNaifSpiceDriver [#600](https://github.com/DOI-USGS/ale/pull/600)
+- Fixed a bug in which quaternions would flip sign in a way that caused interpolation errors [#603](https://github.com/DOI-USGS/ale/issues/603)
 
 ## [0.10.0] - 2024-01-08 
 
diff --git a/ale/rotation.py b/ale/rotation.py
index aa603d6..eaded57 100644
--- a/ale/rotation.py
+++ b/ale/rotation.py
@@ -196,7 +196,27 @@ class TimeDependentRotation:
         the destination reference frame. The quaternions are in scalar
         last format (x, y, z, w).
         """
-        return self._rots.as_quat()
+        quats = self._rots.as_quat()
+
+        # First find the largest magnitude quaternion coefficient and its coordinate
+        num_quats = len(quats)
+        max_q = 0.0
+        max_j = 0
+        for i in range(num_quats):
+            for j in range(4):
+                if abs(quats[i][j]) > abs(max_q):
+                    max_q = quats[i][j]
+                    max_j = j
+
+        # Ensure the signs are consistent
+        qcnt = 0
+        for i in range(num_quats):
+            if quats[i][max_j] * max_q < 0:
+                qcnt = qcnt + 1
+                for j in range(4):
+                    quats[i][j] *= -1.0
+
+        return quats
 
     @quats.setter
     def quats(self, new_quats):
diff --git a/tests/pytests/data/isds/dawnvir_isd.json b/tests/pytests/data/isds/dawnvir_isd.json
index 90674bb..01c3df4 100644
--- a/tests/pytests/data/isds/dawnvir_isd.json
+++ b/tests/pytests/data/isds/dawnvir_isd.json
@@ -339,10 +339,10 @@
     ],
     "quaternions": [
       [
-        -0.08339426680875163,
-        0.2825790922154143,
-        -0.2899354389711647,
-        0.9105667982826637
+        0.08339426680875163,
+        -0.2825790922154143,
+        0.2899354389711647,
+        -0.9105667982826637
       ],
       [
         -0.05753008804150366,
-- 
GitLab