Skip to content

Fix: axis permutations silently erased by transform simplification - #53

Merged
bogovicj merged 2 commits into
imglib:masterfrom
NicoKiaru:test/permutation-not-translation
Jul 3, 2026
Merged

Fix: axis permutations silently erased by transform simplification#53
bogovicj merged 2 commits into
imglib:masterfrom
NicoKiaru:test/permutation-not-translation

Conversation

@NicoKiaru

Copy link
Copy Markdown
Contributor

Fixes #52

Summary

RealViewsSimplifyUtils.isExlusiveTranslation misclassified axis-permutation
matrices as pure translations. simplifyAffineGet then rebuilt them from the
translation column only, silently discarding the permutation: shapes stayed
intact and the translation was roughly right, but the orientation was lost.

Root cause

The classifier coupled the off-diagonal test to val != 1.0:

if ( val != 0.0 && ( ( r == c && val != 1.0 ) || ( c != n && val != 1.0 ) ) ) return false;

For an off-diagonal entry (r != c, c < n) equal to 1.0, neither clause
fires, so it is accepted. The diagonal rule ("must be 1") was wrongly applied to
every in-matrix entry, instead of "off-diagonal must be 0". A concrete Y/Z swap:

[ 1 0 0 | tx ]
[ 0 0 1 | ty ]   <- m12 = 1, off-diagonal, wrongly accepted
[ 0 1 0 | tz ]   <- m21 = 1, off-diagonal, wrongly accepted

passed as a pure translation. A tiny rotation (e.g. 0.5 deg) turns the exact
1.0 entries into 0.9999..., which trips val != 1.0 and accidentally masks
the bug -- explaining why a small "nudge" appeared to fix it.

Fix

Replace the conflated condition with the three explicit rules:

if ( c == n ) { continue; }                            // translation column: any value
if ( r == c ) { if ( val != 1.0 ) return false; }      // diagonal must be 1
else if ( val != 0.0 ) return false;                   // off-diagonal must be 0

Permutations now fail classification and fall through to the lossless generic
affine copy. No information is dropped.

Scope

The sibling classifiers (isExclusiveScale, isExclusiveScaleAndTranslation)
were reviewed and are not affected: both already disqualify any non-zero
off-diagonal entry regardless of value. boundingInterval/estimateBounds use
the full matrix and handle off-diagonal terms correctly. This was the only
erasure path.

The public method name isExlusiveTranslation (sic) is kept unchanged to avoid
breaking API compatibility.

Tests

Added to RealViewsSimplificationsTest (committed first, red before the fix):

  • isExlusiveTranslation must reject PERMUTATION2D / PERMUTATION3D
  • simplifying a permutation must not yield a Translation*
  • simplifying a permutation must preserve the full matrix

Full module test suite passes after the fix.

NicoKiaru and others added 2 commits June 29, 2026 22:56
isExlusiveTranslation currently accepts matrices whose off-diagonal
entries equal 1.0 (e.g. axis permutations), so simplifyAffineGet
collapses them to a pure Translation and silently drops the permutation.

Add tests pinning the expected behaviour:
- isExlusiveTranslation must reject PERMUTATION2D/3D
- simplifying a permutation must not yield a Translation*
- simplifying a permutation must preserve the full matrix

These fail against the current code and document the bug. Also ignore
the IntelliJ /.idea/ directory.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The old test coupled the off-diagonal check to val != 1.0, so an
off-diagonal entry equal to 1.0 (e.g. an axis permutation) was not
disqualified. Such matrices were misclassified as pure translations and
simplifyAffineGet then rebuilt them from the last column only, silently
dropping the permutation.

Replace the conflated condition with the three explicit rules: the
translation column accepts any value, diagonal entries must be 1, and
off-diagonal entries must be 0. Permutations now fall through to the
lossless generic affine copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@bogovicj bogovicj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. This looks good

@bogovicj
bogovicj merged commit 5093398 into imglib:master Jul 3, 2026
1 check passed
@bogovicj

bogovicj commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Thanks @NicoKiaru !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: RealViewsSimplifyUtils: axis permutation are ignored when simplifying to translation

2 participants