Bir noktayı başka bir nokta etrafında döndürme (2D)


139

Kartların çıktığı yerde bir kart oyunu yapmaya çalışıyorum. Şimdi göstermek için bir işlevi olan Allegro API kullanarak Im:

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

bu sayede fan efektimi kolayca yapabilirim. Sorun daha sonra hangi kartın farenin altında olduğunu bilmektir. Bunu yapmak için çokgen çarpışma testi yapmayı düşündüm. Çokgeni oluşturmak için karttaki 4 noktanın nasıl döndürüleceğinden emin değilim. Temel olarak Allegro ile aynı işlemi yapmam gerekiyor.

örneğin, kartın 4 noktası:

card.x

card.y

card.x + card.width

card.y + card.height

Gibi bir işlev gerekir:

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

Teşekkürler

Yanıtlar:


331

Önce pivot noktasını (cx,cy)çıkartın, sonra döndürün, sonra noktayı tekrar ekleyin.

Test edilmemiş:

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
Mükemmel cevap. Kayıt için, ilk turda dönüşü doğru yaptınız.
n.collins

@synchronizer tamamen aynı, sadece nokta çıkarma / toplama rutinleri ve döndürme için vektör * matris işlevinizi kullanın.
Nils Pipenbrinck

8
Günahkârın ve kozanın radyan cinsinden açının ifade edilmesini bekleyebileceğinden bahsetmek için dikkatli olabilirsiniz.
15ee8f99-57ff-4f92-890c-b56153

Pozitif açı değerlerinin sağa (saat yönünde) dönmesini ve negatif bir değer sağlamanın onu sola (saat yönünün tersine) gerçekleştirmesini beklemekte miyim ? Yoksa saat yönünün tersine daha karmaşık bir işlem midir (yani ters açıyı hesaplamak ve daha sonra bu miktarda saat yönünde döndürmek)? Bu aynı formülü veren sayfaların bir ton gördüm ama kimse ... giriş / çıkış değerlerine ilişkin yönelmişlik hakkında konuşmak için uyum görmek görünüyor
NetXpert

72

Eğer noktayı çevirirseniz (px, py)nokta etrafında (ox, oy)açıyla elde edersiniz teta:

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

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

bu, bir noktayı 2D olarak döndürmenin kolay bir yoludur.


7
Döndürmeden sonra geri çevirmeniz gerekir. böylece çözüm şöyle olurdu: p'x + = ox
hAlE

57

Ekrandaki koordinat sistemi solaktır, yani x koordinatı soldan sağa, y koordinatı yukarıdan aşağıya doğru artar. Başlangıç ​​noktası O (0, 0) ekranın sol üst köşesindedir.

resim açıklamasını buraya girin

Bir saat dönme kökenli çevresinde aşağıdaki denklemlerle verilmiştir koordinatları (x, y), bir noktanın:

resim açıklamasını buraya girin

burada (x ', y') dönüş ve açı teta sonrası noktanın koordinatları, dönüş açısı (radyan cinsinden olması gerekir, yani: PI / 180 ile çarpılmalıdır).

O (0,0) orijininden farklı bir nokta etrafında rotasyon yapmak için, A (a, b) noktasını (pivot noktası) diyelim. Öncelikle, pivot noktasının koordinatlarını (x - a, y - b) çıkararak döndürülecek noktayı, yani (x, y) başlangıç ​​noktasına çeviririz. Sonra dönüşü gerçekleştirir ve yeni koordinatları (x ', y') alırız ve son olarak, pivot noktasının koordinatlarını yeni koordinatlara (x '+ a, y' + b) ekleyerek noktayı geri çeviririz.

Yukarıdaki açıklamaya göre:

2B saat derece teta noktasının rotasyon (x, y), bir nokta etrafında (a, b) olduğu:

İşlev prototipinizi kullanarak: (x, y) -> (px, py); (a, b) -> (cx, cy); teta -> açı:

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

Saat yönünde döndürmek için:

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

Saat yönünün tersine dönüş için:

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

Nedir cve s?
TankorSmash

1
@TankorSmash yukarıda tanımlananc = cos(angle)
nycynik

2

Bu Nils Pipenbrinck'in cevabıdır, ancak c # kemanda uygulanır.

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: Görünüşe göre yorum yapamam, bu yüzden cevap olarak göndermek zorundayım ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.