Memutar titik di sekitar titik lain (2D)

144

Saya mencoba membuat permainan kartu di mana kartu menyebar. Sekarang untuk menampilkannya saya menggunakan Allegro API yang memiliki fungsi:

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

jadi dengan ini saya bisa membuat efek kipas saya dengan mudah. Masalahnya adalah mengetahui kartu mana yang ada di bawah mouse. Untuk melakukan ini, saya berpikir untuk melakukan tes tabrakan poligon. Saya hanya tidak yakin bagaimana memutar 4 titik pada kartu untuk membentuk poligon. Saya pada dasarnya perlu melakukan operasi yang sama seperti Allegro.

Misalnya, 4 poin dari kartu tersebut adalah:

card.x

card.y

card.x + card.width

card.y + card.height

Saya membutuhkan fungsi seperti:

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

Terima kasih

jmasterx
sumber

Jawaban:

343

Pertama kurangi titik pivot (cx,cy), lalu putar, lalu tambahkan lagi titik tersebut.

Belum dicoba:

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
sumber
49
Jawaban yang sangat bagus. Sebagai catatan, Anda mendapatkan putaran yang benar untuk putaran pertama.
n. Collins
@synchronizer persis sama, cukup gunakan rutinitas pengurangan / penjumlahan titik dan fungsi matriks * vektor untuk rotasi.
Nils Pipenbrinck
9
Mungkin bermanfaat bagi yang tidak waspada untuk menyebutkan bahwa sin dan cos mungkin mengharapkan sudut diekspresikan dalam radian.
15ee8f99-57ff-4f92-890c-b56153
Apakah saya benar dalam mengharapkan bahwa nilai sudut positif akan melakukan rotasi ke arah kanan (searah jarum jam), dan bahwa memberikan nilai negatif akan melakukannya ke arah kiri (berlawanan arah jarum jam)? Atau apakah berlawanan arah jarum jam merupakan operasi yang lebih rumit (yaitu menghitung sudut terbalik dan kemudian berputar searah jarum jam dengan jumlah tersebut)? Saya telah melihat banyak halaman yang memberikan rumus yang sama ini, tetapi tampaknya tidak ada seorang pun yang merasa cocok untuk membicarakan tentang arah dalam kaitannya dengan nilai input / output ...
NetXpert
74

Jika Anda memutar titik di (px, py)sekitar titik (ox, oy)demi sudut, Anda akan mendapatkan:

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

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

ini adalah cara mudah untuk memutar titik dalam 2D.

enam wajah
sumber
8
Anda perlu menerjemahkan kembali setelah rotasi. jadi solusinya adalah: p'x + = ox
hAlE
2
oxdan oyditambahkan kembali di akhir setiap baris.
BrainSlugs83
58

Sistem koordinat pada layar adalah kidal, yaitu koordinat x bertambah dari kiri ke kanan dan koordinat y bertambah dari atas ke bawah. Asal, O (0, 0) ada di sudut kiri atas layar.

masukkan deskripsi gambar di sini

Sebuah searah jarum jam rotasi di sekitar asal dari titik dengan koordinat (x, y) diberikan oleh persamaan berikut:

masukkan deskripsi gambar di sini

dimana (x ', y') adalah koordinat titik setelah rotasi dan sudut theta, sudut rotasi (perlu dalam radian, yaitu dikalikan dengan: PI / 180).

Untuk melakukan rotasi di sekitar titik yang berbeda dari titik asal O (0,0), katakanlah titik A (a, b) (titik pivot). Pertama kita terjemahkan titik yang akan diputar, yaitu (x, y) kembali ke asalnya, dengan mengurangkan koordinat titik pivot, (x - a, y - b). Kemudian kami melakukan rotasi dan mendapatkan koordinat baru (x ', y') dan akhirnya kami menerjemahkan kembali titik tersebut, dengan menambahkan koordinat titik pivot ke koordinat baru (x '+ a, y' + b).

Berikut uraian di atas:

Rotasi 2D searah jarum jam theta derajat titik (x, y) disekitar titik (a, b) adalah:

Menggunakan prototipe fungsi Anda: (x, y) -> (px, py); (a, b) -> (cx, cy); theta -> sudut:

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

Untuk rotasi searah jarum jam:

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

Untuk rotasi berlawanan arah jarum jam:

float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;
vinay kumar sahu
sumber
Apa cdan s?
TankorSmash
1
@TankorSmash didefinisikan di atasc = cos(angle)
nycynik
3

Ini adalah jawaban dari Nils Pipenbrinck, tetapi diimplementasikan dalam 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: Ternyata saya tidak bisa berkomentar, jadi wajib saya posting sebagai jawaban ...

pengguna umum
sumber