# GL.Rotate and GL.GetFloat or GL.GetDouble gives unprecise result

Posted Friday, 12 February, 2010 - 20:21 by peppebck inHi everybody,

this is my first post and I'm happy to become part of the group...hope I can give some help in the future.

Now I need some information on the reason why I recieve an unprecise Matrix on this simple operation.

This is a big problem for my program and I'd like to know if there's a solution.

Double Ang=90;

Double[]Axis=new double[]{0,0,1};

Double[]rot=new double[16];

GL.Rotate(Ang, Axis[0], Axis[1], Axis[2]);

GL.GetFloat(GetPName.ModelviewMatrix, rot);

This is my matrix, as you can see rot[0] and rot[5] are not zero.

[0] 0.000000012167964413833943 double

[1] 1.0 double

[2] 0.0 double

[3] 0.0 double

[4] -1.0 double

[5] 0.000000012167964413833943 double

[6] 0.0 double

[7] 0.0 double

[8] 0.0 double

[9] 0.0 double

[10] 1.0 double

[11] 0.0 double

[12] 0.0 double

[13] 0.0 double

[14] 0.0 double

[15] 1.0 double

Thanks, and regards.

## Comments

## Re: GL.Rotate and GL.GetFloat or GL.GetDouble gives ...

An amount of numeric imprecision is expected with floating point numbers. This can become an issue when chaining operations - the OpenGL redbook suggests avoiding long chains for precisely that reason. In other words, instead of doing this:

prefer this:

You might be able to get better precision by using OpenTK.Matrix4d instead of the built-in OpenGL matrix functionality. With this approach, you would calculate the modelview matrix by multiplying

`Matrix4d`

instances and would only load the end result with`GL.LoadMatrix`

. For example, the following code:would become:

Pretty verbose but that's necessary to maintain performance. The short version is more readable but also significantly slower:

## Re: GL.Rotate and GL.GetFloat or GL.GetDouble gives ...

Fiddler, thanks for he answer but...the result is just more coerent because the result is orthonormal but it is jet not precise.

I've found the formula used to calculate for example M11:

ux^2 + (1-ux^2)*cos(angle)

and I've found that the problem is on the function Math.Cos (Math.PI).

Math.Cos (Math.PI/2.0) gives the result 6.12303176911189E-17 and not 0 as it should be.

Math.Cos(OpenTK.MathHelper.PiOver2) gives the result 4.37113900018644E-08-

I have to threat my matrix after all the operations...I think (sob)

This is a huge problem. It means a big work of approximation avoiding as you said to chain the operations.

M11 -0.000000043711390001864437 double

M12 0.999999999999999 double

M13 0.0 double

M14 0.0 double

M21 -0.999999999999999 double

M22 -0.000000043711390001864437 double

M23 0.0 double

M24 0.0 double

M31 0.0 double

M32 0.0 double

M33 1.0 double

M34 0.0 double

M41 0.0 double

M42 0.0 double

M43 0.0 double

M44 1.0 double

## Re: GL.Rotate and GL.GetFloat or GL.GetDouble gives ...

Ah,

`OpenTK.MathHelper.PiOver2`

is a float, whereas`System.Math.PI / 2.0`

is a double, which explains the different result. Unfortunately, I don't think it's possible to do any better using floating point numbers, this kind of imprecision is an inherent limitation. Note that OpenGL itself only works with single-precision floats - any double-precision data you pass is converted to single-precision behind the scenes (i.e. when you upload a vertex buffer or a matrix).I'm afraid I'm not well-versed in this area of computing but hopefully someone else will have better advice to offer.

Out of curiosity, what kind of software is this? (And what kind of precision does it require?)

## Re: GL.Rotate and GL.GetFloat or GL.GetDouble gives ...

Duplicate

## Re: GL.Rotate and GL.GetFloat or GL.GetDouble gives ...

Fiddler, I need to place some pieces around models coming from cad. The result has to go back in the cad at the end. So everything has to be precise as much is possible.

I think I'll use the following function to clean my matrix after each rotation.

The idea is to obtain the angle in degrees, clean it if neede and put the Cosine back to the matrix.

Should work but I HAVEN'T tested it jet. Maybe someone can take advantage from this as I did from you.

Thanks a lot.

public static void Clean_Matrix(double[] Matrix)

{

double

ang;

for (int ii = 0; ii < 12; ii += 4)

for (int jj = 0; jj < 4; jj++)

{

ang = Math.Acos(Matrix[ii + jj]) * 180.0 / Math.PI;

if (Math.Round(ang, 1) == Math.Round(ang, 4))

{

if (Math.Abs(ang) == 90)

Matrix[ii + jj] = 0;

else

{

if(ang>90)

Matrix[ii + jj] = Math.Cos(Math.Round(ang, 1));

else

Matrix[ii + jj] = Math.Cos(Math.Round(18.0-ang, 1));

}

}

}

}