Drehen eines Punktes um einen anderen Punkt (2D)


139

Ich versuche ein Kartenspiel zu machen, bei dem die Karten auffächern. Im Moment benutze ich die Allegro-API, die eine Funktion hat:

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

So kann ich meinen Fan-Effekt leicht machen. Das Problem ist dann zu wissen, welche Karte sich unter der Maus befindet. Dazu habe ich mir überlegt, einen Polygonkollisionstest durchzuführen. Ich bin mir nur nicht sicher, wie ich die 4 Punkte auf der Karte drehen soll, um das Polygon zu bilden. Ich muss im Grunde die gleiche Operation wie Allegro durchführen.

Zum Beispiel sind die 4 Punkte der Karte:

card.x

card.y

card.x + card.width

card.y + card.height

Ich würde eine Funktion brauchen wie:

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

Vielen Dank

Antworten:


331

Subtrahieren Sie zuerst den Drehpunkt (cx,cy), drehen Sie ihn dann und fügen Sie den Punkt erneut hinzu.

Ungetestet:

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
Hervorragende Antwort. Für die Aufzeichnung haben Sie beim ersten Mal die richtige Rotation erhalten.
n.collins

@synchronizer genau das gleiche, verwenden Sie einfach Ihre Punktsubtraktions- / Additionsroutinen und Ihre Vektor * Matrixfunktion für die Rotation.
Nils Pipenbrinck

8
Könnte hilfreich sein, wenn Unachtsame erwähnen, dass sin und cos erwarten können, dass der Winkel im Bogenmaß ausgedrückt wird.
15ee8f99-57ff-4f92-890c-b56153

72

Wenn Sie Punkt (px, py)um Punkt (ox, oy)um Winkel Theta drehen, erhalten Sie:

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

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

Dies ist eine einfache Möglichkeit, einen Punkt in 2D zu drehen.


7
Sie müssen nach der Drehung zurück übersetzen. Die Lösung wäre also: p'x + = ox
hAlE

57

Das Koordinatensystem auf dem Bildschirm ist linkshändig, dh die x- Koordinate nimmt von links nach rechts und die y- Koordinate von oben nach unten zu. Der Ursprung O (0, 0) befindet sich in der oberen linken Ecke des Bildschirms.

Geben Sie hier die Bildbeschreibung ein

Eine Drehung im Uhrzeigersinn um den Ursprung eines Punktes mit Koordinaten (x, y) wird durch die folgenden Gleichungen gegeben:

Geben Sie hier die Bildbeschreibung ein

Dabei sind (x ', y') die Koordinaten des Punktes nach der Drehung und der Winkel Theta der Drehwinkel (muss im Bogenmaß angegeben werden, dh multipliziert mit: PI / 180).

Um eine Drehung um einen Punkt durchzuführen, der sich vom Ursprung O (0,0) unterscheidet, sagen wir Punkt A (a, b) (Drehpunkt). Zunächst übersetzen wir den zu drehenden Punkt, dh (x, y), zurück zum Ursprung, indem wir die Koordinaten des Drehpunkts (x - a, y - b) subtrahieren. Dann führen wir die Drehung durch und erhalten die neuen Koordinaten (x ', y') und übersetzen schließlich den Punkt zurück, indem wir die Koordinaten des Drehpunkts zu den neuen Koordinaten (x '+ a, y' + b) addieren.

Nach der obigen Beschreibung:

Eine 2D- Drehung des Punktes (x, y) um Theta-Grad im Uhrzeigersinn um Punkt (a, b) ist:

Verwenden Ihres Funktionsprototyps: (x, y) -> (px, py); (a, b) -> (cx, cy); Theta -> Winkel:

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

Für Drehung im Uhrzeigersinn:

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

Bei Drehung gegen den Uhrzeigersinn:

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

Was ist cund s?
TankorSmash

1
@ TankorSmash seine oben definiertec = cos(angle)
Nycynik

2

Dies ist die Antwort von Nils Pipenbrinck, aber in c # fiddle implementiert.

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: Anscheinend kann ich keinen Kommentar abgeben, daher bin ich verpflichtet, ihn als Antwort zu posten ...

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.