-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make rotations in degrees exact #197
base: master
Are you sure you want to change the base?
Conversation
Codecov Report
@@ Coverage Diff @@
## master #197 +/- ##
==========================================
- Coverage 86.12% 85.84% -0.29%
==========================================
Files 14 14
Lines 1341 1349 +8
==========================================
+ Hits 1155 1158 +3
- Misses 186 191 +5
Continue to review full report at Codecov.
|
Great! I didn't know that the julia> import Unitful.°
julia> sin(30°)
0.5
julia> sin(π/6)
0.49999999999999994 |
Could you change julia> using Rotations; import Unitful.°
julia> RotX(30°)
3×3 RotX{Float64, Quantity{Int64, NoDims, FreeUnits{(°,), NoDims, nothing}}} with indices SOneTo(3)×SOneTo(3)(30°):
1.0 0.0 0.0
0.0 0.866025 -0.5
0.0 0.5 0.866025
julia> RotX(30°)[2,3]
-0.5
julia> AngleAxis(30°,1,0,0)
3×3 AngleAxis{Float64} with indices SOneTo(3)×SOneTo(3)(0.523599, 1.0, 0.0, 0.0):
1.0 0.0 0.0
0.0 0.866025 -0.5
0.0 0.5 0.866025
julia> AngleAxis(30°,1,0,0)[2,3]
-0.49999999999999994 If |
Co-authored-by: Yuto Horikawa <hyrodium@gmail.com>
Co-authored-by: Yuto Horikawa <hyrodium@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add some tests for RotX(30°)
, AngleAxis(30°,1,0,0)
, etc?
I'm in the process of writing extra tests. |
I agree with that. That was already implemented before I joined this package. @andyferris |
Exactitude of coefficients is lost for |
I think we are not using quaternion here, just Rodrigues' rotation formula, (code in this repo).
Exactly. At first, I thought it would be better to have We can choose from the following:
Maybe
Yeah, but it will be hard to express a point on a sphere with a floating-point number... |
But just three lines above your quote: @inline Base.getindex(aa::AngleAxis, i::Int) = UnitQuaternion(aa)[i] Rodrigues formula would indeed be easier for exactness (no angle halving, for a start).
Rational exactness is another useful property 😀 (i.e.
There is this arXiv paper claiming a rational Rodrigues formula. I'm reading it right now; at first sight, it seems legit. Edit: after reading the paper, this comes down to a simple fact: the rotation with axis vector u and angle θ has as coefficients rational functions of (tan(θ/2)/‖u‖) u (and with a denominator at most 1+tan²(θ/2)). For example, in the case of Unfortunately, I believe that the simplest way to cover all those cases is to write ad-hoc code for the case when the angle is a multiple of 30° and the type of the axis vector is exact (integer or rational). |
Ah, I missed the line. julia> aa = rand(AngleAxis)
3×3 AngleAxis{Float64} with indices SOneTo(3)×SOneTo(3)(1.78335, 0.814399, 0.0957725, -0.572347):
0.592207 0.653918 -0.470832
-0.465016 -0.199847 -0.862451
-0.658066 0.729693 0.185732
julia> RotMatrix(aa)[1]
0.5922065228804426
julia> aa[1]
0.5922065228804425 These values
Understood, but I think it will be hard for type stability.
I agree with that. As mentioned above, obtaining exact rational numbers seems to be incompatible with type stability here. Do you think adding the new type parameter |
While searching for the exact Rodrigues formula I found (but did not read) a few papers bout rational approximations for rotation matrices. While that's an interesting option for when the user explicitly asks for a rational answer, that is work for another PR indeed.
For now I reverted
This is due to the fact that |
👍
👍
Ah, bad news. Btw, on the current julia> RotXYZ(30°,60°,90°)
3×3 RotXYZ{Float64} with indices SOneTo(3)×SOneTo(3)(0.523599, 1.0472, 1.5708):
3.06162e-17 -0.5 0.866025
0.866025 -0.433013 -0.25
0.5 0.75 0.433013
julia> RotXYZ(30°,60°,90°)[3,2]
0.75 Hmm, should we drop the accurate calculation of floating-point numbers here..?
I think many users understand that floating-point numbers are approximate calculations, and adding |
In this case
This seems reasonable to me. I expect that code for exact rational rotations is never going to be good as a default codepath for a library which is mainly trying to do fast numerical (floating point) rotations. However, it could be useful to have alternative utility functions which try to go to great lengths to get a good rational answer or approximation. An alternative viewpoint here could be that we accept floating point as a practical necessity, but try to make some of the conversions to rotation matrix elements correctly rounded. For example using compensated floating point arithmetic. This is the point of view that leads to functions like Note that writing correctly rounding code which is fast is very hard though! Practically, it may be better to just use |
The point of the second type parameter is not keeping the angle an integer, it is keeping the angle in degrees, whereas the previous code lost exactness by converting the angle to radians. I expect the standard use case to look more like |
Sure, this is kind of what I was trying to point out: you want the computation to eventually use |
The exact layouts of the structs isn't important to me. This package predates @c42f and I contributing (as well as StaticArrays), so I'm not sure exactly how old those choices are! |
I just stumbled upon this, and though I should bump it. My 2 uninformed cents: It seems like perfect may be the enemy of the good here. |
This PR adds a second type parameter to angular rotations type (
Angle2d
and allRotX
etc.). This prevents automatic conversion of the angle to floating-point and the resulting inexactitude when angles are in degrees.