14
$\begingroup$

I wrote anglecalc to calculate the clockwise angle from line a to b. Initially I thought VectorAngle would do it, but I had to add extra functionality. Is there a simpler way?

rotationangle[{i_, j_}] := Which[
  i >= 0 && j >= 0, VectorAngle[{1, 0}, {i, j}],
  i < 0 && j >= 0, VectorAngle[{0, 1}, {i, j}] + Pi/2,
  i < 0 && j < 0, VectorAngle[{-1, 0}, {i, j}] + Pi,
  i >= 0 && j < 0, VectorAngle[{0, -1}, {i, j}] + 3 Pi/2]

quadrant[{i_, j_}] := Which[
  i >= 0 && j >= 0, 1, i < 0 && j >= 0, 2,
  i < 0 && j < 0, 3, i >= 0 && j < 0, 4]

anglecalc[u_, v_] := Module[{a, theta, r},
  a = VectorAngle[u, v];
  theta = -rotationangle[u];
  r = RotationTransform[theta];
  If[quadrant[r[v]] > 2, 2 Pi - a, a]]

enter image description here

Test cases

r = RotationTransform[90 Degree];

(* case 1 *)
{a, b} = {{{4, 3}, {3, 0}}, {{3, 0}, {10, 1}}};
Graphics[{Arrowheads[0.1], Arrow[{a, b}]}, ImageSize -> {150, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 2 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.22], Arrow[{a, b}]}, ImageSize -> {Automatic, 150}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 3 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.1], Arrow[{a, b}]}, ImageSize -> {150, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 4 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.22], Arrow[{a, b}]}, ImageSize -> {Automatic, 150}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 5 *)
{a, b} = {{{4, 3}, {3, 0}}, {{3, 0}, {10, -7}}};
Graphics[{Arrowheads[0.12], Arrow[{a, b}]}, ImageSize -> {120, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 6 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.09], Arrow[{a, b}]}, ImageSize -> {Automatic, 120}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 7 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.12], Arrow[{a, b}]}, ImageSize -> {120, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 8 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.09], Arrow[{a, b}]}, ImageSize -> {Automatic, 120}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 9 *)
{a, b} = {{{4, 3}, {3, 0}}, {{3, 0}, {-7, -5}}};
Graphics[{Arrowheads[0.1], Arrow[{a, b}]}, ImageSize -> {150, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 10 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.13], Arrow[{a, b}]}, ImageSize -> {Automatic, 150}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 11 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.1], Arrow[{a, b}]}, ImageSize -> {150, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 12 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.13], Arrow[{a, b}]}, ImageSize -> {Automatic, 150}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 13 *)
{a, b} = {{{4, 3}, {3, 0}}, {{3, 0}, {-7, 5}}};
Graphics[{Arrowheads[0.1], Arrow[{a, b}]}, ImageSize -> {150, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 14 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.21], Arrow[{a, b}]}, ImageSize -> {Automatic, 150}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 15 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.1], Arrow[{a, b}]}, ImageSize -> {150, Automatic}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]

(* case 16 *)
{a, b} = r /@ {a, b};
Graphics[{Arrowheads[0.21], Arrow[{a, b}]}, ImageSize -> {Automatic, 150}]
{u, v} = a - b;
N[anglecalc[v, -u] 180/Pi]
$\endgroup$
  • $\begingroup$ First thought occurs to me is to use dot and cross product of 3D vectors. $\endgroup$ – Αλέξανδρος Ζεγγ Apr 26 '18 at 11:12
  • $\begingroup$ You want to find the angle by which a is to be turned clockwise in order to point in the opposite direction of b? $\endgroup$ – LLlAMnYP Apr 26 '18 at 12:31
  • $\begingroup$ @LLlAMnYP My code developed a bit accidentally. The arrows are just to show the Line order, not the vectors. I reversed the direction of one vector in the function call, e.g. anglecalc[v, -u]. $\endgroup$ – Chris Degnen Apr 26 '18 at 13:07
  • $\begingroup$ Might I ask if you're looking for something particularly special in an answer (since you haven't accepted one yet)? $\endgroup$ – LLlAMnYP May 2 '18 at 11:28
  • $\begingroup$ @LLlAMnYP Heh, yes I've found it difficult to choose between your answer and chyanog's because the latter actually shows how VectorAngle can be applied. $\endgroup$ – Chris Degnen May 2 '18 at 11:37
19
$\begingroup$

This passed all test cases, I think:

anglecalc[vec1_, vec2_] := Mod[(ArcTan @@ vec2) - (ArcTan @@ vec1), 2 π]
$\endgroup$
  • 3
    $\begingroup$ Some amazing answers here. $\endgroup$ – Chris Degnen Apr 26 '18 at 12:54
13
$\begingroup$

For a start, you can use this signed-angle function, which involves the two-argument version of ArcTan:

myVectorAngle[{x1_, x2_}, {y1_, y2_}] := Evaluate[
  With[{code = ReIm[(y1 + I y2)/(x1 + I x2)] // ComplexExpand // Simplify},
   ArcTan @@ code]
  ]

Some usage example:

{a, b} = {{{4, 3}, {3, 0}}, {{3, 0}, {10, 1}}} // N;
Pi - myVectorAngle @@ (a - b)

1.10715

If you have to use that a lot, you may switch to the following compiled function:

cf = Block[{P, PP},
   PP = Table[Compile`GetElement[P, i, j, k], {i, 1, 2}, {j, 1, 2}, {k, 1, 2}];
   With[{code = 
      N[Pi] - myVectorAngle[PP[[1, 1]] - PP[[1, 2]], PP[[2, 1]] - PP[[2, 2]]]},
    Compile[{{P, _Real, 3}},
     code,
     CompilationTarget -> "C",
     RuntimeAttributes -> {Listable},
     Parallelization -> True,
     RuntimeOptions -> "Speed"
     ]
    ]
   ];

cf[{a, b}]

1.10715

$\endgroup$
9
$\begingroup$
kek[x_] := 2 \[Pi] - If[x > 0, x, 2 \[Pi] + x]
anglecalc2[u_, v_] := kek[(ToPolarCoordinates[RotationMatrix[{v, {1, 0}}].(u)][[2]])]
$\endgroup$
7
$\begingroup$
anglecalc[u_, v_] := Mod[ArcTan[Dot[u, v], Det[{u, v}]], 2π]

or

anglecalc[u_, v_] := Mod[Sign[Det[{u, v}]] VectorAngle[u, v], 2π]
$\endgroup$
  • $\begingroup$ Really interesting to see an answer making use of VectorAngle, but the answer to this should be Pi, not zero: u = {0, -1}; v = {0, 1}; Mod[Sign[Det[{u, v}]] VectorAngle[u, v], 2 Pi] $\endgroup$ – Chris Degnen May 8 '18 at 10:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.