Rotación de un punto sobre otro punto (2D)

139

Estoy tratando de hacer un juego de cartas donde las cartas se desplieguen. En este momento para mostrarlo estoy usando la API de Allegro que tiene una función:

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

así que con esto puedo hacer que mi ventilador tenga efecto fácilmente. El problema es saber qué tarjeta está debajo del mouse. Para hacer esto, pensé en hacer una prueba de colisión de polígonos. No estoy seguro de cómo rotar los 4 puntos en la tarjeta para formar el polígono. Básicamente necesito hacer la misma operación que Allegro.

por ejemplo, los 4 puntos de la tarjeta son:

card.x

card.y

card.x + card.width

card.y + card.height

Necesitaría una función como:

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

Gracias

jmasterx
fuente

Respuestas:

331

Primero reste el punto de pivote (cx,cy) , luego gírelo, luego agregue el punto nuevamente.

No probado:

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;
}
Nils Pipenbrinck
fuente
45
Excelente respuesta Para el registro, obtuviste la rotación correcta la primera vez.
n.collins
@synchronizer exactamente igual, solo use sus rutinas de resta / suma de puntos y su función de matriz de vectores * para la rotación.
Nils Pipenbrinck
8
Puede ser útil para los incautos mencionar que pecado y cos pueden esperar que el ángulo se exprese en radianes.
15ee8f99-57ff-4f92-890c-b56153
¿Estoy en lo cierto al esperar que los valores positivos de ángulo realizarán una rotación hacia la derecha (en sentido horario), y que proporcionar un valor negativo lo haría hacia la izquierda (en sentido antihorario)? ¿O es en sentido antihorario una operación más complicada (es decir, calcular el ángulo inverso y luego girar en sentido horario en esa cantidad)? He visto un montón de páginas con esta misma fórmula, pero nadie parece considerar apropiado hablar de direccionalidad en relación con los valores de entrada / salida ...
NetXpert hace
72

Si gira punto (px, py)alrededor punto (ox, oy)por ángulo theta obtendrá:

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

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

Esta es una manera fácil de rotar un punto en 2D.

seis caras
fuente
77
Necesita traducir de nuevo después de la rotación. entonces la solución sería: p'x + = ox
hAlE
57

El sistema de coordenadas en la pantalla es zurdo, es decir, la coordenada x aumenta de izquierda a derecha y la coordenada y aumenta de arriba a abajo. El origen, O (0, 0) está en la esquina superior izquierda de la pantalla.

ingrese la descripción de la imagen aquí

Las siguientes ecuaciones dan una rotación en sentido horario alrededor del origen de un punto con coordenadas (x, y):

ingrese la descripción de la imagen aquí

donde (x ', y') son las coordenadas del punto después de la rotación y el ángulo theta, el ángulo de rotación (debe estar en radianes, es decir, multiplicado por: PI / 180).

Para realizar la rotación alrededor de un punto diferente del origen O (0,0), digamos el punto A (a, b) (punto de pivote). Primero, traducimos el punto a rotar, es decir (x, y) de regreso al origen, restando las coordenadas del punto de pivote, (x - a, y - b). Luego realizamos la rotación y obtenemos las nuevas coordenadas (x ', y') y finalmente traducimos el punto hacia atrás, agregando las coordenadas del punto de pivote a las nuevas coordenadas (x '+ a, y' + b).

Siguiendo la descripción anterior:

una rotación 2D en sentido horario theta grados del punto (x, y) alrededor del punto (a, b) es:

Usando su prototipo de función: (x, y) -> (px, py); (a, b) -> (cx, cy); theta -> ángulo:

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);
}
Ziezi
fuente
29
float s = sin(angle); // angle is in radians
float c = cos(angle); // angle is in radians

Para rotación en sentido horario:

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

Para rotación en sentido antihorario:

float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;
vinay kumar sahu
fuente
¿Qué es cy s?
TankorSmash
1
@TankorSmash se define arribac = cos(angle)
nycynik
2

Esta es la respuesta de Nils Pipenbrinck, pero implementada en 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}";
        }
    }
}

PD: Aparentemente no puedo comentar, así que estoy obligado a publicarlo como respuesta ...

usuario genérico
fuente