Rotazione di un punto su un altro punto (2D)


139

Sto cercando di creare un gioco di carte in cui le carte si esauriscono. In questo momento per visualizzarlo Sto usando l'API Allegro che ha una funzione:

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

quindi con questo posso rendere facilmente il mio effetto fan. Il problema è quindi sapere quale carta si trova sotto il mouse. Per fare questo ho pensato di fare un test di collisione poligonale. Non sono sicuro di come ruotare i 4 punti sulla carta per creare il poligono. Fondamentalmente ho bisogno di fare la stessa operazione di Allegro.

ad esempio, i 4 punti della carta sono:

card.x

card.y

card.x + card.width

card.y + card.height

Avrei bisogno di una funzione come:

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

Grazie

Risposte:


331

Prima sottrarre il punto di rotazione (cx,cy), quindi ruotarlo, quindi aggiungere nuovamente il punto.

Non testato:

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
Risposta eccellente. Per la cronaca, hai ottenuto la rotazione corretta al primo giro.
Colle

@synchronizer è esattamente lo stesso, basta usare le routine di sottrazione / addizione dei punti e la funzione matrice * vettoriale per la rotazione.
Nils Pipenbrinck,

8
Potrebbe essere utile per gli incauti dire che peccato e cos possono aspettarsi che l'angolo sia espresso in radianti.
15ee8f99-57ff-4f92-890c-b56153

Ho ragione nell'aspettarmi che i valori positivi di dell'angolo eseguiranno la rotazione di destra (senso orario) e che fornire un valore negativo lo farebbe di sinistra (senso antiorario)? O in senso antiorario è un'operazione più complicata (ovvero calcolare l'angolo inverso e quindi ruotare in senso orario di tale importo)? Ho visto un sacco di pagine che danno la stessa formula, ma nessuno sembra mai
ritenere

72

Se ruoti il ​​punto (px, py)intorno al punto (ox, oy)per angolo, otterrai:

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

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

questo è un modo semplice per ruotare un punto in 2D.


7
Devi tradurre di nuovo dopo la rotazione. quindi la soluzione sarebbe: p'x + = ox
hAlE

57

Il sistema di coordinate sullo schermo è mancino, ovvero la coordinata x aumenta da sinistra a destra e la coordinata y aumenta dall'alto verso il basso. L'origine, O (0, 0) si trova nell'angolo in alto a sinistra dello schermo.

inserisci qui la descrizione dell'immagine

Una rotazione in senso orario attorno all'origine di un punto con coordinate (x, y) è data dalle seguenti equazioni:

inserisci qui la descrizione dell'immagine

dove (x ', y') sono le coordinate del punto dopo la rotazione e l'angolo theta, l'angolo di rotazione (deve essere in radianti, cioè moltiplicato per: PI / 180).

Per eseguire la rotazione attorno a un punto diverso dall'origine O (0,0), diciamo punto A (a, b) (punto di articolazione). Innanzitutto traduciamo il punto da ruotare, ovvero (x, y) di nuovo all'origine, sottraendo le coordinate del punto di rotazione, (x - a, y - b). Quindi eseguiamo la rotazione e otteniamo le nuove coordinate (x ', y') e infine traduciamo il punto indietro, aggiungendo le coordinate del punto pivot alle nuove coordinate (x '+ a, y' + b).

Seguendo la descrizione sopra:

una rotazione 2D di theta gradi in senso orario del punto (x, y) attorno al punto (a, b) è:

Utilizzando il prototipo della funzione: (x, y) -> (px, py); (a, b) -> (cx, cy); theta -> angolo:

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

Per rotazione oraria:

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

Per la rotazione antioraria:

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

Cosa ce s?
TankorSmash,

1
@TankorSmash è definito soprac = cos(angle)
nycynik il

2

Questa è la risposta di Nils Pipenbrinck, ma implementata in 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: Apparentemente non posso commentare, quindi sono obbligato a pubblicarlo come risposta ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.