围绕另一个点旋转一个点(2D)

时间:2010-02-13 23:08:03

标签: c++ algorithm

我正在尝试制作纸牌游戏。现在显示它我使用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)
{
}

由于

6 个答案:

答案 0 :(得分:288)

哦,这很简单..首先减去枢轴点(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;
}

答案 1 :(得分:64)

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

答案 2 :(得分:43)

屏幕上的坐标系是左撇子,即 x 坐标从左到右增加, y 坐标从上到下增加。原点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)来将点转换回来。 / p>

遵循以上描述:

(a,b)周围的点(x,y)的2D顺时针 theta度旋转为:

使用你的函数原型:(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);
}

答案 3 :(得分:21)

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;

答案 4 :(得分:1)

这是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:显然我无法发表评论,所以我有义务将其发布为答案...

答案 5 :(得分:0)

我在使用MS OCR Read API时遇到了麻烦,该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