0

This is more of an optimization problem.

I have given a vector u and a list of vectors v. Now I want to sort the list of vectors v so that the vectors with the smallest counterclockwise angle to u come first and the vectors with the largest counterclockwise angle to u come last. That means I would need to have some kind of function that calculates the counterclockwise angle and then I can use it for the comparison. All vectors are given with x and y coordinates, so I only need it in 2D, and they can all be of different length.

enter image description here

Given such a function I could sort my list like this:

Vector u = ...;
std::sort(vectors.begin(), vectors.end(), [&u](const Vector& v1, const Vector& v2)
    {
        return getAngle(v1, u) < getAngle(v2, u);
    }
);

I already know that there is a way to calculate the angle like this using the dot product, determinant and the atan2 function as answered in this question. But what I need is a more efficient way of doing it without using "slow" functions like division, square root or atan2 (slower in comparison to simple addition or multiplication). The good thing is that I don't need to exactly compute the angle, I just want to know which one is larger (for the sorting algorithm). I know there are some ways to optimize out divisions or square roots for comparisons, like in this example:

sqrt(a*a + b*b) < sqrt(c*c + d*d)
a*a + b*b < c*c + d*d                //doesn't need a sqrt

And comparing the angles with atan2 could look like this:

atan2(dot(v1, u), det(v1, u)) < atan2(dot(v2, u), det(v2, u))

And now I need a way for doing this without the atan2 function for better efficiency.

And I also already know how to compare the angles efficiently using the acos of the dot product divided by the length of the two vectors multiplied:

acos(dot(v1, u) / (v1.length() * u.length())) < acos(dot(v2, u) / (v2.length() * u.length()))
       //remove the acos and flip the comparison operator

dot(v1, u) / (v1.length() * u.length()) > dot(v2, u) / (v2.length() * u.length())
       //remove u.length() from both sides

dot(v1, u) / v1.length() > dot(v2, u) / v2.length()
       //multiply both sides by v1.length() and v2.length()

dot(v1, u) * v2.length() > dot(v2, u) * v1.length()
       //further we could square both sides and use abs on one factor to keep the sign

dot(v1, u) * abs(dot(v1, u)) * v2.lengthSqr() > dot(v2, u) * abs(dot(v2, u)) * v1.lengthSqr()
       //now we can compare the two angles without having any division, sqrt or acos function
       //I hope this method is correct??

But that doesn't always give me the counterclockwise angle, the angle would always be between 0° and 180°.

So, is there some way to modify one of these two algorithms to make it efficient and work for only counterclockwise angles?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Orbit
  • 11
  • 1

0 Answers0