使一点绕另一点旋转(2D)

我想做一个纸牌游戏,把纸牌分散开来。现在使用 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)
{
}

谢谢

248140 次浏览

首先减去枢轴点 (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;
}

如果你将点 (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 中旋转一个点的简单方法。

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;

屏幕上的坐标系是左撇子的,也就是说,X坐标从左到右增加,而 坐标从上到下增加。原点 O (0,0)在屏幕的左上角。

enter image description here

坐标(x,y)点的 顺时针旋转 围绕着原点由下列方程给出:

enter image description here

其中(x’,y’)是旋转后点的坐标和角 θ,旋转角度(需要以弧度为单位,即乘以: PI/180)。

要绕一个与原点 O (0,0)不同的点旋转,我们假设点 A (a,b)(枢轴点)。首先,我们通过减去枢轴点(x-a,y-b)的坐标,将要旋转的点(x,y)转换回原点。 然后我们执行旋转并获得新的坐标(x’,y’) ,最后通过将枢轴点的坐标添加到新的坐标(x’+ a,y’+ b) ,将点转换回来。译注:

以下描述如下:

(x,y)围绕点 (a,b)的2D 顺时针 Θ 度旋转是:

使用函数原型: (x,y)-> (p.x,p.y) ; (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);
}

这是 Nils Pipenbrinck 给出的答案,但是是在 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}";
}
}
}

附: 显然我不能发表评论,所以我有义务把它作为一个答案..。

我挣扎,而工作微软光学字符阅读 API,返回范围内的旋转角度(-180,180]。所以我必须做一个额外的步骤,把负角转换成正角。我希望有人与点旋转与消极或积极的角度可以使用以下。

def rotate(origin, point, angle):
"""
Rotate a point counter-clockwise by a given angle around a given origin.
"""
# Convert negative angles to positive
angle = normalise_angle(angle)


# Convert to radians
angle = math.radians(angle)


# Convert to radians
ox, oy = origin
px, py = point
    

# Move point 'p' to origin (0,0)
_px = px - ox
_py = py - oy
    

# Rotate the point 'p'
qx = (math.cos(angle) * _px) - (math.sin(angle) * _py)
qy = (math.sin(angle) * _px) + (math.cos(angle) * _py)
    

# Move point 'p' back to origin (ox, oy)
qx = ox + qx
qy = oy + qy
    

return [qx, qy]




def normalise_angle(angle):
""" If angle is negative then convert it to positive. """
if (angle != 0) & (abs(angle) == (angle * -1)):
angle = 360 + angle
return angle