Cheap algorithm to find measure of angle between vectors

前端 未结 9 1586
旧时难觅i
旧时难觅i 2020-12-13 01:02

Finding the angle between two vectors is not hard using the cosine rule. However, because I am programming for a platform with very limited resources, I would like to avoid

相关标签:
9条回答
  • 2020-12-13 01:06

    Back in the day of a few K of RAM and machines with limited mathematical capabilities I used lookup tables and linear interpolation. The basic idea is simple: create an array with as much resolution as you need (more elements reduce the error created by interpolation). Then interpolate between lookup values.

    Here is an example in processing (original dead link).

    You can do this with your other trig functions as well. On the 6502 processor this allowed for full 3D wire frame graphics to be computed with an order of magnitude speed increase.

    0 讨论(0)
  • 2020-12-13 01:08

    The cross product is proportional to the angle between two vectors, and when the vectors are normalized and the angle is small the cross product is very close to the actual angle in radians due to the small angle approximation.

    specifically:

    I1Q2-I2Q1 is proportional to the angle between I1Q1 and I2Q2.

    0 讨论(0)
  • 2020-12-13 01:14

    Here on SO I still don't have the privilege to comment (though I have at math.se) so this is actually a reply to Timo's post on diamond angles.

    The whole concept of diamond angles based on the L1 norm is most interesting and if it were merely a comparison of which vector has a greater/lesser w.r.t. the positive X axis it would be sufficient. However, the OP did mention angle between two generic vectors, and I presume the OP wants to compare it to some tolerance for finding smoothness/corner status or sth like that, but unfortunately, it seems that with only the formulae provided on jsperf.com or freesteel.co.uk (links above) it seems it is not possible to do this using diamond angles.

    Observe the following output from my Asymptote implementation of the formulae:

    Vectors : 50,20 and -40,40
    Angle diff found by acos      : 113.199
    Diff of angles found by atan2 : 113.199
    Diamond minus diamond         : 1.21429
    Convert that to degrees       : 105.255
    Rotate same vectors by 30 deg.
    Vectors : 33.3013,42.3205 and -54.641,14.641
    Angle diff found by acos      : 113.199
    Diff of angles found by atan2 : 113.199
    Diamond minus diamond         : 1.22904
    Convert that to degrees       : 106.546
    Rotate same vectors by 30 deg.
    Vectors : 7.67949,53.3013 and -54.641,-14.641
    Angle diff found by acos      : 113.199
    Diff of angles found by atan2 : 113.199
    Diamond minus diamond         : 1.33726
    Convert that to degrees       : 116.971
    

    So the point is you can't do diamond(alpha)-diamond(beta) and compare it to some tolerance unlike you can do with the output of atan2. If all you want to do is diamond(alpha)>diamond(beta) then I suppose diamond is fine.

    0 讨论(0)
  • 2020-12-13 01:14

    dot product of two vectors (x1, y1) and (x2, y2) is

    x1 * x2 + y1 * y2 
    

    and is equivilent to the product of the lengths of the two vectors times the cosine of the angle between them.

    So if you normalize the two vectors first (divide the coordinates by the length)

    Where length of V1 L1 = sqrt(x1^2 + y1^2),  
      and length of V2 L2 = sqrt(x2^2 + y2^2),
    

    Then normalized vectors are

    (x1/L1, y1/L1),  and (x2/L2, y2/L2),  
    

    And dot product of normalized vectors (which is the same as the cosine of angle between the vectors) would be

     (x1*x2 + y1*y2)
     -----------------
         (L1*L2)
    

    of course this may be just as computationally difficult as calculating the cosine

    0 讨论(0)
  • 2020-12-13 01:19

    Have you tried a CORDIC algorithm? It's a general framework for solving polar ↔ rectangular problems with only add/subtract/bitshift + table, essentially doing rotation by angles of the form tan-1 (2-n). You can trade off accuracy with execution time by altering the number of iterations.

    In your case, take one vector as a fixed reference, and copy the other to a temporary vector, which you rotate using the cordic angles towards the first vector (roughly bisection) until you reach a desired angular accuracy.

    (edit: use sign of dot product to determine at each step whether to rotate forward or backward. Although if multiplies are cheap enough to allow using dot product, then don't bother with CORDIC, perhaps use a table of sin/cos pairs for rotation matrices of angles π/2n to solve the problem with bisection.)

    (edit: I like Eric Bainville's suggestion in the comments: rotate both vectors towards zero and keep track of the angle difference.)

    0 讨论(0)
  • 2020-12-13 01:20

    if you need to compute the square root, then consider using the invsqrt hack.

    acos((x1*x2 + y1*y2) * invsqrt((x1*x1+y1*y1)*(x2*x2+y2*y2)));
    
    0 讨论(0)
提交回复
热议问题