# [cairo] Shouldn't Cairo use/offer degrees rather than radians?

Ray Gardener rayg at daylongraphics.com
Wed Jul 12 01:10:32 UTC 2017

```Why not leave the Cairo API alone and implement a utility library analogous
to GLU for OpenGL and that way handy degree-based transform functions
can be put there.

Ray

On 7/11/2017 3:42 PM, Bill Spitzak wrote:
> Your matrix for 45 degrees has equal values in all 4 entries. When
> this matrix is mulitplied by itself you get a matrix made of
> 0.9999999999999998 and 0.0. (That value is actually
> 1.0-2.220446049250313e-16).
>
> If you use the normal sin and cos values (which are unequal to each
> other) you get 1.0 and 2.220446049250313e-16 which is the same
> magnitude of error.
>
> However squaring 0.9999999999999998 gets a number further away from
> 1.0, while squaring 2.220446049250313e-16 goes closer to zero. For
> many operations (such as further multiplies, getting the determinant,
> etc) this means the second matrix is more accurate.
>
>>> You wanted two rotates by 45 degrees to be perfect.
>> Uh, no?  Two rotates by 45 degrees illustrate a _compromise_.  The
>> degree of rotation will generally be a perfect 90 degrees because of all
>> rotation matrix elements having the same magnitude, the total magnitude
>> (determinant of the scaling matrix I think) will lightly be slightly
>> more wrong than the magnitude of the radian API (which likely also fails
>> to be 1 due to sin/cos of M_PI/4 in floating point also being
>> approximations).
> As I tried to show above the answer current Cairo gets for pi/4 is
> better than the one you get for 45 degrees. Your function could be
> improved by using sin and cos rather than trying to do sin(pi/2-a) in
> place of cos in order to make sin and cos equal for 45 degrees.
>
>> Did you even read the patch and its rationale?  Or are you making up
>> that straw man on the fly?  Multiples of 90 degrees are perfect.  There
>> are currently several fast paths in Cairo's code paths which actually
>> _check_ for that kind of perfection.
> I agree there are fast paths that are not allowing such errors in the
> matrix, and that changing cairo_rotate to detect angles near n*pi/2
> and produce 1.0 and 0.0 would probably be a much faster fix than
> trying to track down all the fast path mistakes. It would also remove
> suprises in the matrix for users.
>
>
>>> The exact same value is stored whether the rotation is sent as degrees
>> DID YOU LOOK AT THE PATCH?????  I cannot believe you did when you state
>> this.
> Yes your patch in effect finds the quadrant the angle is in. It
> substitutes sin(pi/2-x) for cos(x) in order to make a right angle have
> a cos of 0.0, however as stated above I believe this is a mistake as
> the determinant of the matrix is not 1.0 for other angles.
>
> My version instead finds the closest axis (or the quadrant if you
> rotate by 45 degrees). The angle passed to sin/cos is in the range
> -pi/4..pi/4. This allows the normal sin/cos functions to be used. Here
> it is (in python sorry):
>
> from math import *
> M_PI_2 = pi/2
>
> # this is needed to avoid producing negative zero:
> def neg(x):
>    return -x if x else 0.0
>
> def sincos(a):
>    axis = round(a / M_PI_2)
>    fromaxis = a - axis * M_PI_2
>    s = sin(fromaxis)
>    c = cos(fromaxis)
>    x = int(axis) & 3
>    if   (x==0): return(     s,     c)
>    elif (x==1): return(     c, neg(s))
>    elif (x==2): return(neg(s), neg(c))
>    else:        return(neg(c), s)
>
> If you think degrees would help then substitute 90 for M_PI_2 and put
> fromaxis*(M_PI_2/90) to the sin and cos function calls. Though
> intuitively it seems like 90*round(a/90) is somehow more accurate than
> M_PI_2*round(a/M_PI_2) I have not been able to find a value where this
> actually happens so I don't believe the degree version is necessary.
>
>>> 2. Add an api to rotate so the x axis passes through an x,y point (and
>>> possibly scales by hypot(x,y)). This would provide an "accurate"
>>> rotate for a whole lot of cases that actually come up in real
>>> graphics.
>> For multiples of 90 degrees, you can "trivially" just specify the
>> transform matrix, yet nobody does.  This is not how people think, and we
>> are talking about an API for people.
> I propose cairo_rotate_atan(x) and cairo_rotate_atan2(x,y) which are
> exactly the same as cairo_rotate(atan(x)) and cairo_rotate(atan2(x,y))
> except for greater accuracy. The hope is that it is obvious how to fix
> code that is using atan to get the angle. You are right that no matter
> what happens, lots of code is going to continue to use
> cairo_rotate(M_PI/2), so I think fixing that function is a good idea.

```