2013-05-12 14 views
7

Używam algorytmu skanowania Grahama do znalezienia wypukłego kadłuba zestawu punktów Próbuję posortować punkty według ich kąta biegunowego, ale nie mam pojęcia, jak to zrobić (Posortowałem już zbiór punktów według ich współrzędnych Y).Sortowanie punktów według ich kąta biegunowego w Javie

Co ja już napisałem jest tak:

public double angle(Coord o, Coord a) 
{ 
    return Math.atan((double)(a.y - o.y)/(double)(a.x - o.x)); 
} 

gdzie Coord jest klasa gdzie mam współrzędne X i Y jako double.

Przyjrzałem się także jednemu z podobnych stanowisk w Stack Overflow, w którym ktoś próbował zaimplementować ten kąt w C++, ale nie rozumiem qsqrt. Czy mamy coś takiego w Javie?

qreal Interpolation::dp(QPointF pt1, QPointF pt2) 
{ 
    return (pt2.x()-pt1.x())/qSqrt((pt2.x()-pt1.x())*(pt2.x()-pt1.x()) + (pt2.y()-pt1.y())*(pt2.y()-pt1.y())); 
} 

Będę zadowolony, jeśli ktoś może mi pomóc.

Odpowiedz

12

Nie trzeba obliczyć kąta biegunowego, aby go posortować. Ponieważ funkcje trygonometryczne są monotoniczne (zawsze rosnące lub zawsze maleją) w kwadrancie, wystarczy posortować według samej funkcji, np. opalenizna w twoim przypadku. Jeśli wdrażasz skanowanie Grahama zaczynając od najniższego punktu, wystarczy spojrzeć na pierwsze dwa kwadraty, aby najłatwiej było posortować je według cotana, ponieważ jest monotoniczny względem obu ćwiartek.

Innymi słowy, możesz sortować według - (x - x1)/(y - y1) (gdzie (x1, y1) są współrzędnymi punktu początkowego), które będą szybsze do obliczenia. Najpierw musisz oddzielić punkty, gdzie y == y1, oczywiście, i dodać je na górze lub na dole listy w zależności od znaku (x - x1) `, ale są łatwe do zidentyfikowania, ponieważ już masz posortowane według y, aby znaleźć punkt początkowy.

+0

i co powinienem użyć w java, aby znaleźć wzór dla cotana? po prostu zamień mój kod na: publiczny podwójny kąt (Coord o, Coord a) { powrót 1.0/Math.tan ((podwójne) (a.y - o.y)/(podwójne) (a.x - o.x)); } –

+0

dla punktu, od którego zaczyna się, gdzie jest napisane inaczej. ma znaczenie, od czego zacząć? –

+2

'(x - x1)/(y - y1)' jest formułą dla cotan (1/tan) - sąsiadującą z przeciwną. Występowałem tylko w negatywie, aby wzrastało pod kątem. Nie słyszałem o skanowaniu Grahama, więc oparłem moją odpowiedź na artykule w Wikipedii, który sugeruje, że zaczyna się od najniższego punktu. Pomysł się nie zmieni, jeśli zaczniesz od, powiedzmy, od lewej strony. W takim przypadku najłatwiej byłoby użyć stycznej: '(y - y1)/(x - x1)' – maybeWeCouldStealAVan

0

Math.atan() zwraca kąt między -pi/2 do pi/2. Będziesz musiał dostosować wyniki dla dwóch pozostałych współrzędnych.

Jeśli chcesz uzyskać kąt ze środka wypukłego kadłuba, musisz najpierw przetłumaczyć współrzędne, tak aby pochodziło centroid.

5

Jak wspomniano powyżej, obliczanie kąta biegunowego jako takiego jest dość niedbałym sposobem postępowania. Możesz zdefiniować prosty komparator i używać produktów krzyżowych do sortowania według kąta biegunowego. Oto kod w C++ (którego używam na moim Algorytm Grahama):

struct Point { 
    int x, y; 
} 

int operator^(Point p1, Point p2) { 
    return p1.x * p2.y - p1.y * p2.x; 
} 

bool operator<(Point p1, Point p2) 
{ 
    if(p1.y == 0 && p1.x > 0) 
     return true; //angle of p1 is 0, thus p2 > p1 

    if(p2.y == 0 && p2.x > 0) 
     return false; //angle of p2 is 0 , thus p1 > p2 

    if(p1.y > 0 && p2.y < 0) 
     return true; //p1 is between 0 and 180, p2 between 180 and 360 

    if(p1.y <0 && p2.y > 0) 
     return false; 

    return (p1^p2) > 0; //return true if p1 is clockwise from p2 
} 

można zaimplementować samo w Javie, definiując klasę Point. Zasadniczo przeciąłem operatora ^, aby zwrócić produkt krzyżowy. Reszta jest oczywista, mam nadzieję, że to pomoże!

Powiązane problemy