8

I want to know how to get an angle of a line A-B from horizontal axis X. Other questions in SO do that only between two lines. I'm aware I can always draw second line A-C and calculate but I'm wondering if there's a faster method.

EDIT: I'm very sure I'm not doing a premature optimization.

VOX
  • 2,883
  • 2
  • 33
  • 43
  • 2
    Be wary of premature optimization. Have you profiled the code? – Charlie Salts Jun 30 '10 at 22:31
  • 1
    I can't understand the down votes. Is this a silly question? or is if offensive? hmm.. – VOX Jun 30 '10 at 22:37
  • 1
    @VOX - Post your profiling results. Prove to yourself that you need a faster solution. – Charlie Salts Jun 30 '10 at 22:43
  • @Charlie, imagine a situation you have to get the angle tens of thousands of times in a .NET CF mobile device, you will want to make it as fast as possible. – VOX Jun 30 '10 at 22:43
  • 1
    "want[ing] to make it as fast as possible" is the problem. First you should want to make it work. Then if it doesn't perform satisfactorily, you find out what's causing the problem and fix it. – Cogwheel Jun 30 '10 at 22:46
  • Thanks for comments anyway. Two people already answered my question without arguing I should ask the question or not. I'm enough with their answer. :) – VOX Jun 30 '10 at 22:49
  • 3
    I'm pretty sure this is a legitimate question. The answer is so simple an easy-to-understand that there is no reason **not** to use it. This is not a case where premature optimization makes things harder to understand or more complicated. This actually simplifies things. – Justin L. Jun 30 '10 at 22:54
  • 1
    Last few times anyone asked me this it turned out that the only thing they did with the angle later was compute a trig function of it, like `sin` or `cos`. If that's true in this case, and you care about performance, it's likely that you shouldn't actually compute the angle. But it's only possible to make a recommendation based on what you intend to do with the angle. – sigfpe Jun 30 '10 at 23:48

6 Answers6

12

You can use atan for that.

angle = atan((By-Ay)/(Bx-Ax))
Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
11
    private double Angulo(int x1, int y1, int x2, int y2)
    {
        double degrees;

        // Avoid divide by zero run values.
        if (x2 - x1 == 0)
        {
            if (y2 > y1)
                degrees = 90;
            else
                degrees = 270;
        }
        else
        {
            // Calculate angle from offset.
            double riseoverrun = (double)(y2 - y1) / (double)(x2 - x1);
            double radians = Math.Atan(riseoverrun);
            degrees = radians * ((double)180 / Math.PI);

            // Handle quadrant specific transformations.       
            if ((x2 - x1) < 0 || (y2 - y1) < 0)
                degrees += 180;
            if ((x2 - x1) > 0 && (y2 - y1) < 0)
                degrees -= 180;
            if (degrees < 0)
                degrees += 360;
        }
        return degrees;
    }
Fernando
  • 111
  • 1
  • 2
2

If you need all four quadrants, Atan2 is more suitable than Atan.

public static int GetAngleBetweenPoints(PointF pt1, PointF pt2)
{
    float dx = pt2.X - pt1.X;
    float dy = pt2.Y - pt1.Y;

    int deg = Convert.ToInt32(Math.Atan2(dy, dx) * (180 / Math.PI));
    if (deg < 0) { deg += 360; }

    return deg;
}
CtrlDot
  • 3,102
  • 3
  • 25
  • 32
1

If

  1. The angle is small,
  2. you can live with small inaccuracies, and
  3. You can use the angle in radians and not degrees,

then there is a fast solution: Under these conditions, you can assume that tan(a) = a = atan(a), and hence just omit the atan() call.

Frank
  • 2,628
  • 15
  • 14
  • "tan(a) = a = atan(a)" Eh...what? – Bart van Heukelom Jul 01 '10 at 08:23
  • @Bart van Heukelom: Yes, as I wrote, this is not exact, but a good approximation for small angles. E. g. tan(0.1) = 0.1003, tan(0.2) = 0.203 So for angles in this range, if you do not need absolute precision, you can save some calculation effort. – Frank Jul 01 '10 at 08:40
  • Yes, that seems to be true. The inaccuracies already get too large once the angle is larger than about 10 degrees though, and I think that if you're dealing with small angles you'll usually want the highest precision anyway. – Bart van Heukelom Jul 02 '10 at 09:17
  • @Bart: As the OP stated that performance with limited resources is very important, I just wanted to make him aware of this optimization possibility which may or may not be a solution for the problem, as he did not state anything about the typical or worst case size of the angles. – Frank Jul 02 '10 at 09:45
1

You could also use arccosine, if your line is in the form [r_x,r_y], where r_x is the change in x and r_y is the change in y.

angle = arccos( r_x/( r_x*r_x + r_y*r_y ) )

It's slightly more opaque, but it's basically the dot product law:

angle = arccos (r . v)

Where r and v are both unit vectors (vectors of length 1). In our case, v is the vector [1,0], and r is

[r_x,r_y] / (r_x^2+r_y^2)

in order to make it a unit vector.

Justin L.
  • 13,510
  • 5
  • 48
  • 83
0

The x-axis is actually a line with equation

y = 0

so you could use the solution you have already.

Charlie Salts
  • 13,109
  • 7
  • 49
  • 78