ポイントを別のポイントを中心に回転(2D)


139

私はカードがファンアウトするカードゲームを作ろうとしています。現在、機能を備えたAllegro APIを使用してそれを表示します。

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

これでファンのエフェクトを簡単に作ることができます。問題は、マウスの下にあるカードを知ることです。これを行うには、ポリゴンの衝突テストを行うことを考えました。カードの4点を回転させてポリゴンを作成する方法がわかりません。基本的にはアレグロと同じ操作が必要です。

たとえば、カードの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 2012年

@シンクロナイザはまったく同じです。回転には、ポイント減算/加算ルーチンとvector * matrix関数を使用してください。
Nils Pipenbrinck 2017年

8
罪とcosが角度がラジアンで表されることを期待するかもしれないことを不注意に言及するのに役立つかもしれません。
15ee8f99-57ff-4f92-890c-b56153 '19年

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')は、回転後の点の座標と角度theta、回転角度です(ラジアン単位である必要があります。つまり、PI / 180を掛けます)。

原点O(0,0)とは異なる点を中心に回転を実行するには、点A(a、b)(ピボットポイント)としましょう。最初に、ピボットポイントの座標(x-a、y-b)を引くことにより、回転するポイント、つまり(x、y)を原点に戻します。次に、回転を実行して新しい座標(x '、y')を取得し、最後にピボットポイントの座標を新しい座標(x '+ a、y' + b)に追加して、ポイントを元に戻します。

上記の説明に従ってください。

(a、b)の周りの点(x、y)の 2D時計回りのシータ度回転は次のとおりです。

関数プロトタイプを使用:(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 2017年

1
@TankorSmash上で定義されたものc = cos(angle)
nycynik 2017年

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

Ps:どうやらコメントできないので、回答として投稿する義務があります...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.