다른 점을 기준으로 점 회전 (2D)


139

카드가 펼쳐지는 곳에서 카드 게임을 만들려고합니다. 현재 기능을 가진 Allegro API를 사용하여 Im을 표시하려면 다음을 수행하십시오.

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

이것으로 팬 효과를 쉽게 만들 수 있습니다. 문제는 마우스 아래에있는 카드를 아는 것입니다. 이를 위해 다각형 충돌 테스트를 생각했습니다. 카드의 4 포인트를 회전시켜 다각형을 구성하는 방법을 잘 모르겠습니다. 기본적으로 Allegro와 동일한 작업을 수행해야합니다.

예를 들어, 카드의 4 포인트는 다음과 같습니다.

card.x

card.y

card.x + card.width

card.y + card.height

다음과 같은 기능이 필요합니다.

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

감사

답변:


331

먼저 피벗 점을 빼고 (cx,cy)회전 한 다음 점을 다시 추가하십시오.

테스트되지 않은 :

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
훌륭한 답변입니다. 기록을 위해, 당신은 처음 회전 올바른 회전을 얻었다.
n.collins

@synchronizer는 정확히 동일합니다. 포인트 빼기 / 추가 루틴과 벡터 * 행렬 함수를 사용하여 회전하십시오.
Nils Pipenbrinck

8
죄와 죄가 각도를 라디안으로 표현하기를 기대할 수 있다는 경고에 대해 경고 할 때 도움이 될 수 있습니다.
15ee8f99-57ff-4f92-890c-b56153

72

각도 세타별로 점을 (px, py)중심으로 점 을 회전하면 다음과 같은 결과가 나타 (ox, oy)납니다.

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

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

이것은 포인트를 2D로 회전시키는 쉬운 방법입니다.


7
회전 후 다시 번역해야합니다. 해결책은 다음과 같습니다. p'x + = ox
hAlE

57

화면의 좌표계는 왼손잡이입니다. 즉, x 좌표가 왼쪽에서 오른쪽으로 증가 하고 y 좌표가 위에서 아래로 증가합니다. 원점 O (0, 0)는 화면의 왼쪽 상단에 있습니다.

여기에 이미지 설명을 입력하십시오

시계 회전 원점 주위 이하의 식으로 주어진다 좌표 (x, y)를 갖는 점 :

여기에 이미지 설명을 입력하십시오

여기서 (x ', y')는 회전 후 점과 각도 세타의 좌표, 회전 각도입니다 (라디안이어야 함, 즉 PI / 180을 곱해야 함).

원점 O (0,0)과 다른 점을 중심으로 회전을 수행하려면 점 A (a, b) (피벗 점)를 예로 들어 보겠습니다. 먼저 피벗 점의 좌표 (x-a, y-b)를 빼서 회전 할 포인트, 즉 (x, y)를 원점으로 다시 변환합니다. 그런 다음 회전을 수행하고 새 좌표 (x ', y')를 가져오고 마지막으로 피벗 점의 좌표를 새 좌표 (x '+ a, y'+ b)에 추가하여 점을 다시 변환합니다.

위의 설명에 따라 :

2 차원 방향으로 도 세타 지점의 회전 (X, Y)에 점을 중심으로 (a, b) 이다 :

함수 프로토 타입 사용 : (x, y)-> (px, py); (a, b)-> (cx, cy); 세타-> 각도 :

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

시계 방향 회전 :

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

시계 반대 방향 회전 :

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

무엇 cs?
TankorSmash

1
@TankorSmash 위에서 정의한c = cos(angle)
nycynik

2

이것은 Nils Pipenbrinck의 답변이지만 c # 바이올린으로 구현되었습니다.

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}";
        }
    }
}

추신 : 분명히 말할 수 없으므로 답변으로 게시해야합니다 ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.