Rotating vectors in space and high accuracy in C ++

This is my function for calculating 3D rotation in C ++, determined by the radiant angle around the axis.

Vector rotate(const Vector& axis, const Vector& input, const double angle) { double norm = 1/axis.norm(); if(norm != 1) axis *= norm; double cos = std::cos(angle); double mcos = 1 - cos; double sin = std::sin(angle); double r1[3]; double r2[3]; double r3[3]; double t_x, t_ym t_z; r1[0] = cos + std::pow(axis.x, 2)*mcos; r1[1] = axis.x*axis.y*mcos - axis.z * sin; r1[2] = axis.x*axis.z*mcos - axis.y * sin; r2[0] = axis.x*axis.y*mcos + axis.z*sin; r2[1] = cos + std::pow(axis.y, 2)*mcos; r2[2] = axis.x*axis.z*mcos - axis.x * sin; r3[0] = axis.x*axis.z*mcos - axis.y * sin; r3[1] = axis.z*axis.y*mcos - axis.x * sin; r3[2] = cos - std::pow(axis.z, 2) * mcos; return Vector(t_x, t_y, t_z); } 

The fact is that if you try to rotate the vector a n times pi/4 , where n multiple of 4 (so that you make a complete revolution around the axis, performing four quarters of the revolution), the error will propagate quite quickly.

Example (where err = input-output ):

 input: (1.265, 3.398, 3.333) rotation axis: (2.33, 0.568, 2.689) n: 8 (so two completes revolutions) output: (1.301967, 1.533389, 4.138940) error: (0.038697, -0.864611, 0.805940) n: 400 (so 100 completes revolutions) error: (472..., 166..., 673...) 

What can I do?

Limitations:

  • Rotations are not predictable, therefore it is impossible to do something like angle = pi/4 *n % 2*pi , as @molbdnilo suggests. Because I need to link translations and rotations to check if there is a collision.
+8
c ++ precision
source share
4 answers

In the end, I used the Rodrigs rotation formula , and the performances were better.

Although this is not a solution, as @ComicSansM points to this:

Avoid the float chain of operations first!

Thus, combining the new algorithm and using the Rodriguez formula was in order.

I suspect errors in my first matrix implementation.

Thank you all for your answers and ideas.

0
source share

This is one of the typical problems you may encounter with float s.

Floating-point numbers are pretty accurate in special operations. In fact, for many operations you are guaranteed to get the most accurate result that can be presented in a format, so any rounding errors that you get are solely connected with the substitution of the view.

However, as soon as you start a chain of floating point operations, even these errors can accumulate. If you're lucky, you can make your algorithm numerically stable so that rounding errors eventually cancel each other out and you always remain in the focus of the correct result. Obtaining this right can be quite a challenge, especially for complex calculations. For example, in your particular implementation there are many possibilities for catastrophic cancellation , introducing large rounding errors into the computation chain.

An easier solution: Avoid the float chain of operations first! Or, to be more precise: combine only those parts that you can keep numerically stable. Since you mentioned this for a computer game: in the game you transform the geometry according to the camera matrix in each frame. You never touch the geometry in memory; instead, you simply adjust the camera matrix. Thus, your original geometry is always fresh, and the rounding error in each frame is simply an error from this single transformation.

Similarly, you usually do not update the camera matrix gradually. Instead, you read the player’s position and view and build the complete matrix from scratch from these vectors. Now the only problem that you are facing is that you do not accumulate errors in the position and viewing of the player, but this is much easier than ensuring stability at the other end of the transformation pipeline.

+3
source share

Just save the original base vector and rotation angle together and do the calculations every time you need the current rotated value. You can cache this and invalidate each time you change the angle, but always work with the original base vector and complete rotation of the aggregate.

Presto! There are no cumulative errors because there are no chain calculations.

In addition, if you are concerned about cumulative errors in the corner itself, store them in degrees and convert to radians when necessary. Again, pi touch once in the degree-> radian conversion, and you don't have a chain of approximate pi/n values ​​contributing to more errors.

0
source share

You can try and sample your rotations so that they add to the pi / 2 multiples. You clamp your rotation value to the nearest discretized value, and then perform the calculation. If you find it small enough, it will still be perceived as smooth, and you should not accumulate a mistake.

0
source share

All Articles