Obracanie punktu wokół innego punktu (2D)


139

Próbuję stworzyć grę karcianą, w której karty się rozkładają. W tej chwili do wyświetlenia używam API Allegro, które ma funkcję:

al_draw_rotated_bitmap(OBJECT_TO_ROTATE,CENTER_X,CENTER_Y,X
        ,Y,DEGREES_TO_ROTATE_IN_RADIANS);

więc dzięki temu mogę łatwo uzyskać efekt wachlarza. Problem polega na tym, aby wiedzieć, która karta jest pod myszą. Aby to zrobić, pomyślałem o wykonaniu testu zderzenia wielokątów. Po prostu nie jestem pewien, jak obrócić 4 punkty na karcie, aby utworzyć wielokąt. Zasadniczo muszę wykonać tę samą operację co Allegro.

na przykład 4 punkty na karcie to:

card.x

card.y

card.x + card.width

card.y + card.height

Potrzebowałbym funkcji takiej jak:

POINT rotate_point(float cx,float cy,float angle,POINT p)
{
}

Dzięki

Odpowiedzi:


331

Najpierw odejmij punkt obrotu (cx,cy), następnie obróć go, a następnie dodaj ponownie.

Nieprzetestowane:

POINT rotate_point(float cx,float cy,float angle,POINT p)
{
  float s = sin(angle);
  float c = cos(angle);

  // translate point back to origin:
  p.x -= cx;
  p.y -= cy;

  // rotate point
  float xnew = p.x * c - p.y * s;
  float ynew = p.x * s + p.y * c;

  // translate point back:
  p.x = xnew + cx;
  p.y = ynew + cy;
  return p;
}

45
Doskonała odpowiedź. Dla przypomnienia, obrót był prawidłowy za pierwszym razem.
n.collins

@synchronizer dokładnie to samo, po prostu użyj procedur odejmowania / dodawania punktów i funkcji macierzy wektorowej * do obracania.
Nils Pipenbrinck

8
Dla nieostrożnych może być pomocne wspomnienie, że sin i cos mogą oczekiwać, że kąt będzie wyrażony w radianach.
15ee8f99-57ff-4f92-890c-b56153

72

Jeśli obrócisz punkt (px, py)wokół punktu (ox, oy)o kąt theta, otrzymasz:

p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox

p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

jest to łatwy sposób na obrócenie punktu w 2D.


7
Musisz przetłumaczyć z powrotem po obrocie. tak więc rozwiązanie byłoby następujące: p'x + = ox
hAlE

57

Układ współrzędnych na ekranie jest lewoskrętny, tzn. Współrzędna x rośnie od lewej do prawej, a współrzędna y od góry do dołu. Początek O (0, 0) znajduje się w lewym górnym rogu ekranu.

wprowadź opis obrazu tutaj

Do ruchu wskazówek zegara obrót dookoła punktu początkowego w punkcie o współrzędnych (x, y) jest wyrażona przez następujące równania:

wprowadź opis obrazu tutaj

gdzie (x ', y') to współrzędne punktu po obrocie i kąt theta, czyli kąt obrotu (należy podać w radianach, czyli pomnożone przez: PI / 180).

Aby wykonać obrót wokół punktu innego niż punkt początkowy O (0,0), powiedzmy punkt A (a, b) (punkt obrotu). Najpierw tłumaczymy obrócony punkt, tj. (X, y) z powrotem do punktu początkowego, odejmując współrzędne punktu obrotu (x - a, y - b). Następnie wykonujemy obrót i otrzymujemy nowe współrzędne (x ', y'), a na końcu dokonujemy translacji punktu z powrotem, dodając współrzędne punktu obrotu do nowych współrzędnych (x '+ a, y' + b).

Zgodnie z powyższym opisem:

a obrót punktu (x, y) w kierunku zgodnym z ruchem wskazówek zegara theta wokół punktu (a, b) wynosi:

Używając prototypu funkcji: (x, y) -> (px, py); (a, b) -> (cx, cy); theta -> kąt:

POINT rotate_point(float cx, float cy, float angle, POINT p){

     return POINT(cos(angle) * (p.x - cx) - sin(angle) * (p.y - cy) + cx,
                  sin(angle) * (p.x - cx) + cos(angle) * (p.y - cy) + cy);
}

29
float s = sin(angle); // angle is in radians
float c = cos(angle); // angle is in radians

Obrót w prawo:

float xnew = p.x * c + p.y * s;
float ynew = -p.x * s + p.y * c;

Obrót w lewo:

float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;

Co ci s?
TankorSmash

1
@TankorSmash to zdefiniowane powyżejc = cos(angle)
nycynik

2

To jest odpowiedź Nilsa Pipenbrincka, ale zaimplementowana w c # fiddle.

https://dotnetfiddle.net/btmjlG

using System;

public class Program
{
    public static void Main()
    {   
        var angle = 180 * Math.PI/180;
        Console.WriteLine(rotate_point(0,0,angle,new Point{X=10, Y=10}).Print());
    }

    static Point rotate_point(double cx, double cy, double angle, Point p)
    {
        double s = Math.Sin(angle);
        double c = Math.Cos(angle);
        // translate point back to origin:
        p.X -= cx;
        p.Y -= cy;
        // rotate point
        double Xnew = p.X * c - p.Y * s;
        double Ynew = p.X * s + p.Y * c;
        // translate point back:
        p.X = Xnew + cx;
        p.Y = Ynew + cy;
        return p;
    }

    class Point
    {
        public double X;
        public double Y;

        public string Print(){
            return $"{X},{Y}";
        }
    }
}

Ps: Najwyraźniej nie mogę komentować, więc mam obowiązek zamieścić to jako odpowiedź ...

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.