หมุนจุดเกี่ยวกับจุดอื่น (2D)


139

ฉันกำลังพยายามสร้างเกมไพ่ที่การ์ดจะเปิดออก ตอนนี้เพื่อแสดงมันโดยใช้ Allegro API ซึ่งมีฟังก์ชั่น:

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
อาจเป็นประโยชน์สำหรับผู้ที่ไม่ระวังที่จะพูดถึงว่าบาปและ cos อาจคาดหวังมุมที่แสดงออกเป็นเรเดียน
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, y) กลับไปที่จุดกำเนิดโดยการลบพิกัดของจุดหมุน (x - a, y - b) จากนั้นเราทำการหมุนและรับพิกัดใหม่ (x ', y') และสุดท้ายเราแปลจุดกลับโดยการเพิ่มพิกัดของจุดหมุนไปยังพิกัดใหม่ (x '+ a, y' + b)

ทำตามคำอธิบายข้างต้น:

2D ตามเข็มนาฬิกาtheta องศาการหมุนของจุด(x, y)รอบจุด(a, b)คือ:

การใช้ฟังก์ชั่นต้นแบบของคุณ: (x, y) -> (px, py); (a, b) -> (cx, cy); theta -> มุม:

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;

อะไรcและs?
TankorSmash

1
@TankorSmash กำหนดไว้ข้างต้นc = cos(angle)
nycynik

2

นี่คือคำตอบของ Nils Pipenbrinck แต่นำไปใช้ในซอ # 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: เห็นได้ชัดว่าฉันไม่สามารถแสดงความคิดเห็นดังนั้นฉันจึงจำเป็นต้องโพสต์มันเป็นคำตอบ ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.