0

Given following problem:

enter image description here

I have 2 solutions:

First is to calculate difference in absolute angles, then renormalize angle. bad idea, 2 x atan2() is slow, renormalisation is inefficient.

  • angle = clamp_to_range( atan2(P1.y, P1.x) - atan2(P0.y, P0.x));

Second is to calculate dot product, normalize, calculate arccos(). Also bad idea, because angle sign will be incorrect.

  • angle = acos( dot(P0, P1) / sqrt( dot(P0,P0) * dot(P1, P1) ) );

I feel, that there should be some formula. How to solve given problem efficiently?

xakepp35
  • 2,878
  • 7
  • 26
  • 54
  • @Yves Daoust My apologies. I was too hurry, missed that you already had given key moments, and wrote my answer automatically. (cannot delete accepted answer now) – MBo Feb 27 '18 at 16:45
  • @Mbo Yours is better. It has some illustration code (without one closing bracket at the end). And his answer dont even mention parameter order for cross product, thus was considered lower quality. I asked him to correct, he deleted his answer because of, citing, "setting acceptance conditions was unacceptable" to him. – xakepp35 Feb 28 '18 at 19:30

2 Answers2

2

It is possible to use only one atan2 but both cross product and scalar product of vectors:

angle = atan2(Cross(P0, P1), Dot(P0, P1);
MBo
  • 77,366
  • 5
  • 53
  • 86
1

Do you really need the angle in radians / degrees, instead of as a unit vector or rotation matrix?

An xy unit vector can represent angle instead of absolute direction; the angle is the angle between the vertical (or horizontal) axis and the unit vector. Trig functions are very slow compared to simple multiply / add / subtract, and still slow compared to div / sqrt, so representing angles as vectors is usually a good thing.

You can calculate its components using the Cross(P0, P1) and Dot(P0, P1), but then normalize them into an xy unit vector instead of using atan2 on them.

See also Rotate Object Towards Direction in 2D on gamedev.SE, and Is it better to track rotation with a vector or a float?


This is easy to vectorize with SIMD, much moreso than a SIMD atan2. rsqrtps exists mostly to speed up x *= 1.0 / sqrt(foo) (and reusing the same multiplier for a SIMD vector of y values) for normalization. But rsqrtps is very low accuracy so you often need a Newton Raphson iteration to refine. The most recent CPUs (Skylake) have good FP sqrt / div throughput, so you could just normalize the naive way with _mm_sqrt_ps and leave optimization for later. See Fast vectorized rsqrt and reciprocal with SSE/AVX depending on precision.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847