Description
I just encountered a very tricky silent bug while slinging around AffineMap
, LinearMap
, Transformation
etc.
In summary, I have some 3D rotation matrices stored as LinearMap
and tried to combine it with a translation stored as Vector
. Spot the error in this code:
using CoordinateTransformations, Rotations
rot = LinearMap(RotY(1/2*pi))
# ...
loc = rand(3)
# ...
pose_map = AffineMap(rot, loc)
# ...
f(pmap::AffineMap) = ...
@test f(pose_map) == test_value # <- compiles just fine, but result completely wrong
It turns out that AffineMap(::LinearMap, ::Vector)
actually calls an overloaded function AffineMap(::Transformation, ::Any)
and returns an AffineMap just fine, but with AffineMap.v == zeros(3)
!
CoordinateTransformations.jl/src/affine.jl
Lines 121 to 125 in b97c74a
I.e.
# continued
@assert pose_map.linear == rot.linear # true
@assert pose_map.translation == loc # false. instead
@assert pose_map.translation == zeros(length(loc)) # <- 🤯
This is a super tricky bug, as it's completely silent, and occurs from a "misuse" of the interface that is very subtle.
Perhaps it would make sense to rename the function
function AffineMap(trans::Transformation, x0)
dT = transform_deriv(trans, x0)
Tx = trans(x0)
AffineMap(dT, Tx - dT*x0)
end
to something like AffineMapApprox
(or something similar), although I realize that would be a breaking change.
Alternatively, we could overload AffineMap(::LinearTransformation, ::Any)
, e.g. giving a warning like
@warn "
AffineMap(rot::LinearTransformation, ::Any)
might not do what you want. TryAffineMap(rot.linear, x)
instead."