Jak mogę stwierdzić, czy obiekt porusza się w kierunku CW lub CCW wokół połączonej ścieżki?

19

Powiedzmy, że mamy postrzępiony kształt:

kształt 0

I dwa stworzenia poruszające się po obrysie.

Następnie całkowicie wygładzamy kształt, wyciągając rogi.

Otrzymujemy to:

gładki

Teraz widać, że Orange porusza się w kierunku CW, a zielony w kierunku przeciwnym. Jak mogę określić, w którym kierunku się poruszają, bez wygładzania kształtu?

Nowy wygląd

wprowadź opis zdjęcia tutaj

wolfdawn
źródło
Oto moje 2 centy: i.imgur.com/zrBdw.png
Kendall Frey

Odpowiedzi:

27

Narysuj linię do nieskończoności i policz, ile razy przekroczysz kształt (parzysty lub nieparzysty), nie licząc segmentu, w którym leży stworzenie. Następnie sprawdź, czy stwór idzie w lewo, czy w prawo od tej linii.

przykład

W tym przykładzie przecinamy kształt dwa razy (więc nawet) i idziemy w lewo. Wynik jest natychmiastowy z tej tabeli:

   # Crosses | even  | odd
  Direction  |       |
-------------+-------+------
    left     | CCW   |  CW
    right    |  CW   | CCW

W pseudokodzie:

x, y = position of creature
vx, vy = direction of creature movement
crossings = 0
for each x1, y1, x2, y2 in shape segments:
    if (x1 < x and x <= x2) or (x2 < x and x <= x1):
        if y - y1 > (x - x1) * (y2 - y1) / (x2 - x1):
            ++crossings
if (crossings & 1) == (vx < 0):
    return CW
else
    return CCW
sam hocevar
źródło
czy dołączasz kreaturę idącą dalej?
Ali1S232,
@Gajoo: nie, stąd> zamiast> = w linii 6. Dodam notatkę na ten temat. Pamiętaj jednak, że możesz dołączyć wiersz i po prostu odwrócić zawartość tabeli.
sam hocevar,
1
Rzucałem się między udzieleniem odpowiedzi opartej na tej metodzie a odpowiedzią, której udzieliłem. Cieszę się, że mamy tutaj reprezentowane oba podejścia. Ten jest koncepcyjnie prostszy i bardzo elegancki, ale wymaga przeprowadzenia testów przecięcia segmentu linii, co może być trudne, aby uczynić go solidnym.
Trevor Powell,
@TrevorPowell True. Znalezienie najdalszej krawędzi może być mylące. Najpierw sprawdziłem na podstawie najbardziej odległego wierzchołka krawędzi, a następnie narysowałem linię ze środka kształtu i przez środki dwóch krawędzi (dwóch, które dzielą wierzchołek) i sprawdziłem, czy jedna z linii przecina drugą krawędź w drodze do nieskończoność po przekroczeniu jednej z tych krawędzi. Udało się
Wolfdawn
5

Zależy to od tego, jakie informacje masz dostępne ze struktury danych kształtu, ale stworzenie poruszające się CW wzdłuż konturu kształtu zawsze będzie miało wnętrze kształtu po prawej stronie, a stworzenie poruszające się w kierunku przeciwnym do ruchu będzie miało wnętrze kształtu na jego lewa strona.

Jeff
źródło
O wiele prostsze rozwiązanie, a także moja pierwsza myśl.
Amplify91
skąd wiesz, który kierunek jest wewnątrz kształtu? Mam na myśli, że poruszanie się wzdłuż krawędzi wewnątrz kształtu jest albo po lewej, albo po prawej stronie. skąd wiesz, która to jest droga?
Ali1S232,
Bardzo eleganckie rozwiązanie, ale ogólnie nie jest prawdą. Wyobraź sobie pączka spłaszczonego na stole, aby uzyskać dwuwymiarowy kształt. Możesz przejść wzdłuż krawędzi tego kształtu, zachować wnętrze kształtu po lewej stronie i wykonać okrążenie zgodnie z ruchem wskazówek zegara lub przeciwnie do ruchu wskazówek zegara, w zależności od miejsca rozpoczęcia.
Marcks Thomas
4
  1. Oblicz punkt środkowy swojego kształtu.
  2. Wybierz najodleglejszą krawędź swojego kształtu od środka.
    • (Wybranie najbardziej odległej krawędzi gwarantuje, że nie zaczniesz od odwróconej, wklęsłej części kształtu, co spowodowałoby cofnięcie oznaczenia w prawo / w lewo dla całego kształtu)
  3. Określ kierunek wzdłuż tej krawędzi zgodnie z ruchem wskazówek zegara
    • (Prosta implementacja tego wymagałaby porównania kątów od środka kształtu do każdego końca wybranej krawędzi. Znak różnicy między kątami pokaże twój ruch w prawo lub w lewo)
  4. Iteruj po wszystkich krawędziach kształtu, zaczynając od krawędzi wybranej w kroku 2, tworząc listę krawędzi. Dla każdej krawędzi przechowuj jej dwa wierzchołki w kolejności zgodnej z ruchem wskazówek zegara.
    • (Jeśli twój kształt nie zmienia się w czasie, możesz zapisać tę listę krawędzi do późniejszego wykorzystania, więc nie musisz robić pierwszych czterech kroków w każdej klatce)
    • (być może masz już listę krawędzi. Jeśli tak, możesz zapisać tę kolejność wierzchołków zgodnie z ruchem wskazówek zegara na tej samej liście).
  5. Aby ustalić, czy jednostka porusza się w prawo czy w lewo:
    • Określ, na której krawędzi porusza się jednostka.
    • Wykonaj iloczyn iloczynu kierunku ruchu bytu względem wektora od wierzchołków tej krawędzi zgodnie z ruchem wskazówek zegara -> wierzchołków, które określiłeś w kroku 4.
    • Jeśli wynik iloczynu jest wartością większą od zera, jednostka porusza się zgodnie z ruchem wskazówek zegara. Mniej niż zero oznacza przeciwnie do ruchu wskazówek zegara.
Trevor Powell
źródło
Bardzo sprytna odpowiedź
wolfdawn
Mam małe pytanie? zakładając, że wierzchołki w jego kształcie są ponumerowane, zaczynając od najbardziej lewego punktu CWW, w oparciu o twoją odpowiedź, jak mogę stwierdzić, czy przejście od 6-> 7 lub 9-> 10 (w oparciu o zero) odbywa się zgodnie z ruchem wskazówek zegara?
Ali1S232,
Zaczynasz od najodleglejszej krawędzi i zastanawiasz się, która droga jest zgodna z ruchem wskazówek zegara na tej krawędzi. Powiedzmy, że krawędź A jest zgodna z ruchem wskazówek zegara od wierzchołka „a” do „b”. Następnie, jeśli przejdziemy do krawędzi B (która ma wierzchołki „b” i „c”), wiemy, że B jest zgodne z ruchem wskazówek zegara od „b” do „c”. Podobnie krawędź C będzie skierowana zgodnie z ruchem wskazówek zegara od „c” do „d”. Gdy znamy prawidłowy kierunek zgodny z ruchem wskazówek zegara z jednej krawędzi (kroki 1-3), kontynuując ten kierunek zgodny z ruchem wskazówek zegara wokół krawędzi kształtu, możemy wydedukować prawidłowy kierunek „zgodny z ruchem wskazówek zegara” dla każdej krawędzi, bez faktycznego patrzenia na lokalizację jej krawędzi, więc wklęsłość jest w porządku.
Trevor Powell,
skąd możesz wiedzieć, czy krawędź A jest zgodna z ruchem wskazówek zegara od „a” do „b” lub czy jest zgodna z ruchem wskazówek zegara od „b” do „a”? Myślę, że tęskniłeś za tą częścią.
Ali1S232,
@Gajoo To jest nawiasowy punkt na kroku 3. Prawdopodobnie nie powinien być nawiasowy, ponieważ tak naprawdę jest to krytyczny etap całego procesu.
Trevor Powell,
2

Musisz wiedzieć, w którą stronę zdefiniowany jest wielokąt, w którą stronę otaczają go wierzchołki.

Jeśli nie wiesz o tym, możesz to rozwiązać, obliczając powierzchnię wielokąta:

float Polygon::area() {
    float result = 0.0f;

    for(int a = 0; a < vertexCount; a ++) {
        int b = (a+1) % vertexCount;
        result += vertices[a].x * vertices[b].y;
        result -= vertices[a].y * vertices[b].x;
    }

    return result * .5f;
}

Znak wyniku (dodatniego lub ujemnego) powie, czy jest to prawo lub w lewo. Musisz spróbować, aby sprawdzić, która z tych opcji jest dla Ciebie, ponieważ zależy to od układu współrzędnych.

Jeśli kształt jest zgodny z ruchem wskazówek zegara:

  • Stworzenie poruszające się dookoła kształtu porusza się zgodnie z ruchem wskazówek zegara i
  • Stworzenie poruszające się do tyłu wokół kształtu idzie w kierunku przeciwnym do ruchu wskazówek zegara .

Jeśli kształt jest przeciwny do ruchu wskazówek zegara:

  • Stworzenie poruszające się dookoła kształtu idzie w kierunku przeciwnym do ruchu wskazówek zegara , i
  • Stwór poruszający się dookoła kształtu porusza się zgodnie z ruchem wskazówek zegara .
Chris Burt-Brown
źródło
0

Wygląda na to, że Trevor już omówił to pytanie, ale oto moje rozwiązanie:

  1. obliczyć obszar, który pokrywa twój kształt, co oznacza

    area = 0
    foreach (edge in shape)
        area += edge.begin.x * edge.end.y - edge.begin.y * edge.end.x
  2. używając obszaru obliczonego jak wyżej, możesz łatwo stwierdzić, czy sam kształt jest zgodny z ruchem wskazówek zegara, czy nie. jest zgodny z ruchem wskazówek zegara tylko wtedy, gdy obszar jest poniżej zera.

  3. sprawdź, czy obiekty poruszają się w taki sam sposób, jak wierzchołki są uporządkowane, czy w przeciwnym kierunku.

Ali1S232
źródło
Powiązane: stackoverflow.com/questions/1165647/…
Trevor Powell,