Find the Angle ( as Measured in Counter Clock Wise Direction) Between Two Edges

The way to get the smaller angle spanned by $\mathbf e_1=(x_1,y_1)$ and $\mathbf e_2=(x_2,y_2)$ is through the expression

$\min(|\arctan(x_1,y_1)-\arctan(x_2,y_2)|,2\pi-|\arctan(x_1,y_1)-\arctan(x_2,y_2)|)$

where $\arctan(x,y)$ is the two-argument arctangent.


The answer by J.M. is correct, but depending on how you are calculating these, it might be much more efficient to use the method you initially proposed. Specifically note that (as shown in your question) $\sin\,\theta$ is proportional to the magnitude of the cross product and $\cos\,\theta$ is proportional to the dot product. Importantly, the constant of proportionality is the same for both. Now, assume we construct a new vector: $$\mathbf {e_3}=(|e_1\cdot e_2|, |e_1\times e_2|)=(r \cos\,\theta, r \sin\,\theta) \quad \textrm{ where } \quad r={|e_1||e_2|}$$ It's clear from the above that $\mathbf {e_3}$ is a vector with magnitude $r$ oriented at angle $\theta$. So we can use the x and y components of $\mathbf {e_3}$ to calculate the angle.

dot = x1*x2 + y1*y2      # dot product of e1 and e2
det = x1*y2 - y1*x2      # determinant (same as magnitude of cross product)
angle = atan2(det, dot)  # atan2(y, x) or atan2(sin, cos)

Note that whereas J.M.'s answer makes 4 calls to atan2 (which could be reduced to 2), this method makes only one call, along with some simple operations. Thus it's likely to be more computationally efficient, but that depends on the calculation environment.

Note that atan2 has its arguments reversed in some calculation environments (e.g. Spreadsheets, etc): atan2(x, y), so make sure you are passing them in the right order: cos corresponds to x and sin corresponds to y.

Note

As others have pointed out, this method may in some cases cause overflow (due to the multiplication of coordinates) and/or precision loss (due to addition/subtraction of products that could have drastically different magnitudes). This again depends on the computation environment and the datatypes used to represent the numbers involved.

It might be necessary or desirable in some cases to check for the conditions that would result in overflow or precision loss and to use an alternative method (like the accepted answer) when necessary.