Wiem, że to pytanie jest dość stare, a zaakceptowana odpowiedź pomogła mi to osiągnąć, wciąż myślę, że mam bardziej eleganckie rozwiązanie, które obejmuje również równość (tak zwraca -1 dla niższegoTana, 0 dla równych i 1 dla Lepszy niż).
Oparta jest na podziale płaszczyzny na 2 połówki, jedną z dodatniej osi refowania (włącznie) na ujemną oś ref (wyłącznie), a druga jest jej dopełnieniem.
Wewnątrz każdej połówki porównania można dokonać za pomocą reguły prawej ręki (znak krzyża produktu) lub innymi słowy - znaku sinusa kąta między 2 wektorami. Jeśli 2 punkty pochodzą z różnych połówek, porównanie jest proste i odbywa się między samymi połówkami.
Dla odpowiednio jednolitej dystrybucji, test ten powinien wykonywać średnio 4 porównania, 1 odejmowanie i 1 mnożenie, oprócz 4 odejmowań wykonanych przy pomocy ref, które według mnie powinny być wstępnie obliczone.
int compareAngles(Point const & A, Point const & B, Point const & ref = Point(0,0)) {
typedef decltype(Point::x) T; // for generality. this would not appear in real code.
const T sinA = A.y - ref.y; // |A-ref|.sin(angle between A and positive ref-axis)
const T sinB = B.y - ref.y; // |B-ref|.sin(angle between B and positive ref-axis)
const T cosA = A.x - ref.x; // |A-ref|.cos(angle between A and positive ref-axis)
const T cosB = B.x - ref.x; // |B-ref|.cos(angle between B and positive ref-axis)
bool hA = ((sinA < 0) || ((sinA == 0) && (cosA < 0))); // 0 for [0,180). 1 for [180,360).
bool hB = ((sinB < 0) || ((sinB == 0) && (cosB < 0))); // 0 for [0,180). 1 for [180,360).
if (hA == hB) {
// |A-ref|.|B-ref|.sin(angle going from (B-ref) to (A-ref))
T sinBA = sinA * cosB - sinB * cosA;
// if T is int, or return value is changed to T, it can be just "return sinBA;"
return ((sinBA > 0) ? 1 : ((sinBA < 0) ? (-1) : 0));
}
return (hA - hB);
}
Po prostu ciekawy, w którym zrobiłeś zdjęcie? – TMS
Zakładam, że masz na myśli produkt dot? Dla mnie to wygląda na 2D. Trudno powiedzieć. –
Nie sądzę, żebyś mógł używać przynajmniej iloczynów, wszystkie wektory musiałyby być tej samej długości, a nawet wtedy otrzymasz tylko cosinus kąta. –