Repository navigation
BUG: Invert scaled and skewed versor transforms without throwing - #7056
hjmjohnson wants to merge 2 commits into
Conversation
f68707c to
41e5c39
Compare
|
Force-push (content only, same base): |
41e5c39 to
5a9e4b1
Compare
|
Force-push (content only, same base): the round-trip check now also verifies forward(inverse(p)) == p, for every case that uses it. |
5a9e4b1 to
52f224c
Compare
|
Force-push (content only, same base): split into a |
|
Downstream check: this PR restores 121 BRAINSTools tests that pass on ITK
DetailsRun in the downstream build forest (ITK built with every default module and Python wrapping, then BRAINSTools and ANTs built against it with
|
This comment was marked as resolved.
This comment was marked as resolved.
|
Confirmed on the current head |
52f224c to
b2bdfad
Compare
ScaleVersor3DTransform, ScaleSkewVersor3DTransform and ComposeScaleSkewVersor3DTransform inherit VersorRigid3DTransform's GetInverseTransform(), which builds the inverse as a rigid versor transform, so Versor::Set() throws on the scaled or skewed matrix. Invert them to a MatrixOffsetTransformBase, as the base class does. The test checks each inverse in both directions and rebuilt from its parameters.
Its ComputeMatrixParameters() decomposes a matrix into rotation, scale and skew, so its inverse can keep the concrete type, as the other versor transforms' inverses do. When the decomposed rotation is not orthogonal to within Versor::Set()'s tolerance, as with a large skew, return the MatrixOffsetTransformBase inverse instead of throwing.
b2bdfad to
e8562cc
Compare
|
Two force-pushes: |
RESTORE ITK v5.4 compatibility. A seldom-used optional tool built into BRAINSTools identified this regression. I don't think any other tools in my ITK forest are affected. This set of fixes restores the previous behavior.
ScaleVersor3DTransform,ScaleSkewVersor3DTransform, andComposeScaleSkewVersor3DTransformthrow "matrix does not represent rotation" fromGetInverseTransform()inmain. They inherit the same-type override that b025291 (#6686) added toVersorRigid3DTransform, so the inverse of a scaled or skewed rotation is built as a pure rotation.BUG:all three invert to aMatrixOffsetTransformBase, as the base class does.ENH:ComposeScaleSkewVersor3DTransformthen inverts to its own type, falling back to aMatrixOffsetTransformBasewhen its rotation cannot be recovered (for example, a skew of 50).Downstream impact: BRAINSTools inverts transforms when writing them, and 111 of its 416 tests fail against ITK
main(its CI pinsrelease-5.4, which predates the change).Root cause and why the types differ
Transform::InvertTransform(const TTransform &)creates the inverse asTTransform, the static type at the call site.VersorRigid3DTransform::GetInverseTransform()calls it with*thisas aVersorRigid3DTransform, so aScaleVersor3DTransformgets aVersorRigid3DTransforminverse.GetInverse()then hands it the scaled matrix, and itsComputeMatrixParameters()callsVersor::Set(matrix), which rejects a matrix that is not a rotation.ScaleVersor3DTransformadds a diagonal scale to the rotation matrix (R + diag(s − 1)); the inverse of such a matrix is generally not one, and itsComputeMatrixParameters()throws.ScaleSkewVersor3DTransformadds scale and six skew terms; it can represent any matrix, but with no unique decomposition, and itsComputeMatrixParameters()throws. A same-type inverse would need a decomposition convention (for example the polar rotation plus the remainder as scale and skew) and is left for a separate change.ComposeScaleSkewVersor3DTransformcomposes rotation, scale, and skew (R·S·K), and itsComputeMatrixParameters()decomposes a matrix that way, so it can keep its type. Its Gram–Schmidt decomposition loses orthogonality for large skew or extreme scale, andVersor::Set()(tolerance 1e-10) then throws; the second commit returns the base inverse in that case.These three are the only subclasses of the classes b025291 changed that lacked an override of their own (
CenteredEuler3DTransformandSimilarity3DTransformhave theirs).Testing
macOS arm64, conda clang, Release,
Module_ITKTransform=ON; each commit builds with 0 warnings and passes all 61ITKTransformtests, andpre-commit run --all-filespasses.itkTestTransformGetInversenow, for each non-identity case:GetInverseTransform()and reports it for that class, so one failure no longer hides the others;New cases: a rotated, anisotropically scaled, and (where applicable) skewed instance of each class, plus a
ComposeScaleSkewVersor3DTransformwith a skew of 50. Without the first commit's header change all three classes fail with the exception BRAINSTools hits; without the fallback, the skew-50 case fails the same way.Found while testing #7041 in the downstream build forest: BRAINSTools'
BRAINSTransformConvertMakeTestFilesaborts on this exception, and most of the 111 failures are tests that read the files it never writes.AI assistance (Claude Code) was used to find the defect and draft the change; it was reviewed and tested locally.