Girando um ponto sobre outro ponto (2D)

139

Estou tentando fazer um jogo de cartas onde as cartas se espalham. Agora, para exibi-lo, estou usando a API Allegro, que tem uma função:

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

então com isso eu posso fazer meu efeito de fã facilmente. O problema é saber qual cartão está sob o mouse. Para fazer isso, pensei em fazer um teste de colisão de polígono. Só não sei como girar os 4 pontos no cartão para formar o polígono. Basicamente, preciso fazer a mesma operação que o Allegro.

por exemplo, os 4 pontos do cartão são:

card.x

card.y

card.x + card.width

card.y + card.height

Eu precisaria de uma função como:

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

obrigado

jmasterx
fonte

Respostas:

331

Primeiro subtraia o ponto de articulação (cx,cy), gire-o e adicione o ponto novamente.

Não testado:

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
fonte
45
Excelente resposta. Para o registro, você conseguiu a rotação correta na primeira vez.
N
@ sincronizador exatamente o mesmo, basta usar suas rotinas de subtração / adição de pontos e sua função de matriz vetorial * para rotação.
Nils Pipenbrinck 2/17/17
8
Pode ser útil para os incautos mencionarem que pecado e cos podem esperar que o ângulo seja expresso em radianos.
15ee8f99-57ff-4f92-890c-b56153
72

Se você girar ponto em (px, py)torno de ponto (ox, oy)por ângulo teta, obterá:

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

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

Essa é uma maneira fácil de girar um ponto em 2D.

seis cara
fonte
7
Você precisa traduzir novamente após a rotação. então a solução seria: p'x + = ox
hAlE
57

O sistema de coordenadas na tela é canhoto, ou seja, a coordenada x aumenta da esquerda para a direita e a coordenada y aumenta de cima para baixo. A origem, O (0, 0) está no canto superior esquerdo da tela.

insira a descrição da imagem aqui

Uma rotação no sentido horário em torno da origem de um ponto com coordenadas (x, y) é dada pelas seguintes equações:

insira a descrição da imagem aqui

onde (x ', y') são as coordenadas do ponto após a rotação e o ângulo teta, o ângulo de rotação (precisa estar em radianos, isto é, multiplicado por: PI / 180).

Para executar a rotação em torno de um ponto diferente da origem O (0,0), digamos o ponto A (a, b) (ponto de articulação). Primeiramente, convertemos o ponto a ser rotacionado, ou seja, (x, y) de volta à origem, subtraindo as coordenadas do ponto de articulação (x - a, y - b). Em seguida, executamos a rotação e obtemos as novas coordenadas (x ', y') e, finalmente, convertemos o ponto de volta, adicionando as coordenadas do ponto de articulação às novas coordenadas (x '+ a, y' + b).

Seguindo a descrição acima:

um teta 2D no sentido horário graus de rotação do ponto (x, y) ao redor do ponto (a, b) é:

Usando seu protótipo de função: (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
fonte
29
float s = sin(angle); // angle is in radians
float c = cos(angle); // angle is in radians

Para rotação no sentido horário:

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

Para rotação no sentido anti-horário:

float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;
vinay kumar sahu
fonte
O que é ce s?
TankorSmash
1
@TankorSmash está definido acimac = cos(angle)
nycynik 25/11
2

Esta é a resposta de Nils Pipenbrinck, mas implementada em 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: Aparentemente, não posso comentar, por isso sou obrigado a publicá-la como resposta ...

usuário genérico
fonte