Use atan2 function instead of atan – EasyHack

When working with shapes and charts in LibreOffice, there are several occasions that you have to calculate tan-1x. But is atan function always the best choice? Here we discuss using atan2 function instead of atan in C++ code. When used in correct place, atan2 can have a lot of benefits when calculating atan ( y / x ).

Unit circle

Unit circle

If you use atan(x) to calculate the output θ, you have to think about different situations that may occur, because with the same value of x, there are multiple values of θ, and it would be your responsibility to handle that, and find out what is the suitable value of θ.

But, if you have two values y and x, and you want to calculate atan(y / x), there is a better choice: using atan2(y, x). As discussed here, atan2(y, x) can handle the values from all the 4 different quadrants.

This is the formula for atan2(y, x):

atan2 formula

atan2 formula

In this way, you don’t have to check the sign of x and y because atan2() does this by itself.

There are some places in the LibreOffice core that is currently using atan, and atan2 is more suitable. For example, in hwpfilter/source/hcode.cxx:

1447 double angle;
1448 angle = (180 / PI) * atan( ( y2 - y1 ) * 1.0 / ( x2 - x1 ));
1449 if( y2 >= y1 ){ /* 1, 2 quadrant */
1450      if( angle < 0. )
1451            angle += 180.;
1452 }
1453 else{ /* 3, 4 quadrants */
1454      if( angle > 0 )
1455            angle += 180.;
1456      else
1457            angle += 360.;
1458 }

A better choice would be this one single line:

1458 double angle = basegfx::rad2deg(atan2(y2 - y1 , x2 - x1));

Instead of multiplying the output of atan() by (180 / PI) to get degrees out of radians, we simply use basegfx::rad2deg() for the conversion, and also using the atan2(), those conditions would be superfluous, and are removed.

Finding instances of atan to replace with atan2

This grep command shows the instances of the similar situations:

git grep atan\(

Within the results of the grep, you can find places that atan2() is better. You should take care about the conditions that may be present (or missing) after the atan(). These conditions usually check the sign of the numerator and denominator in the fraction passed to atan(). Make sure that the code works correctly after removing them.

Final Notes

Besides fixing the bugs, there are many places to work on improving the code, and some of these are listed as EasyHacks. The specific improvement that is discussed in this blog post is filed as tdf#145630, and you can submit patches for this improvement  to LibreOffice Gerrit.

If you want to work on this improvement, but you need to know how to get started with LibreOffice development, I suggest you to see our video tutorial:

Getting Started (Video Tutorial)