fix(gtx): extractRealComponent returns the canonical (non-negative) real part - #1446
fix(gtx): extractRealComponent returns the canonical (non-negative) real part#1446Osamaali313 wants to merge 2 commits into
Conversation
…eal part
extractRealComponent reconstructs a quaternion's real component from its
x/y/z as sqrt(1 - x^2 - y^2 - z^2), but returned the NEGATIVE root. The
function already clamps the radicand with `if (w < 0) return 0`, signalling
a non-negative result, yet then negates it -- so for any canonical unit
quaternion (w >= 0) it returns the wrong sign (e.g. a 60-degree rotation
about X has true w = +0.8660254 but the function returned -0.8660254; the
identity quaternion returns -1 instead of +1).
Return the positive root, matching the documented purpose ("extract the
real component") and the standard reconstruction convention. Adds a
regression test -- the function had no test coverage.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Fixes the sign of glm::extractRealComponent so it returns the canonical (non-negative) real component, and adds a regression test to prevent returning the negated value.
Changes:
- Corrected
extractRealComponentto returnsqrt(w)instead of-sqrt(w)for valid inputs. - Added a new unit test validating that extraction returns a non-negative
wand matches the canonical quaternion.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/gtx/gtx_quaternion.cpp | Adds a regression test covering extractRealComponent’s expected (non-negative) output. |
| glm/gtx/quaternion.inl | Fixes the sign bug in extractRealComponent by removing the unintended negation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // A canonical unit quaternion (60 degrees about X): w = cos(30 deg) >= 0. | ||
| glm::quat const q(0.8660254f, 0.5f, 0.0f, 0.0f); | ||
| float const w = glm::extractRealComponent(q); | ||
|
|
||
| // Reconstructing the real component from x/y/z must recover the canonical | ||
| // (non-negative) w, not its negation. | ||
| Error += glm::epsilonEqual(w, q.w, 0.0001f) ? 0 : 1; | ||
| Error += (w >= 0.0f) ? 0 : 1; |
Per review: replace the hard-coded quaternion literals with glm::angleAxis(glm::radians(60), X) and compare against glm::cos(Angle/2), so the test is self-describing and free of magic numbers.
|
Thanks @copilot — done in 8b954a7. The test now builds the quaternion with |
Problem
glm::extractRealComponentreconstructs a quaternion's real component from its imaginary parts assqrt(1 - x² - y² - z²), but it returns the negative root:The function is internally contradictory: it clamps the radicand with
if (w < 0) return 0— signalling a non-negative magnitude — and then returns-sqrt(w), which is always ≤ 0. So for any canonical unit quaternion (w ≥ 0) it returns the wrong sign:extractRealComponent(0.8660254, 0.5, 0, 0)(1, 0, 0, 0)This contradicts the documented purpose ("Extract the real component of a quaternion") and the standard reconstruction convention (the canonical real part of a unit quaternion is the non-negative root — the same
w = sqrt(1 - x² - y² - z²)used when reconstructing a quaternion stored as x/y/z only).Fix
Return the positive root (
sqrt(w)).Tests
The function had no test coverage (which is why the sign error went unnoticed). Added
test_extractRealComponenttotest/gtx/gtx_quaternion.cpp: it builds a canonical unit quaternion, extracts the real component, and asserts it recovers the truewand is non-negative. (Fails on the old-sqrt, passes on the fix.)