Rotating a point about another point (2D)

Viewed 241260

I'm trying to make a card game where the cards fan out. Right now to display it Im using the Allegro API which has a function:

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

so with this I can make my fan effect easily. The problem is then knowing which card is under the mouse. To do this I thought of doing a polygon collision test. I'm just not sure how to rotate the 4 points on the card to make up the polygon. I basically need to do the same operation as Allegro.

for example, the 4 points of the card are:

card.x

card.y

card.x + card.width

card.y + card.height

I would need a function like:

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

Thanks

6 Answers

First subtract the pivot point (cx,cy), then rotate it, then add the point again.

Untested:

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;
}

This is the answer by Nils Pipenbrinck, but implemented in 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: Apparently I can’t comment, so I’m obligated to post it as an answer ...

I struggled while working MS OCR Read API which returns back angle of rotation in range (-180, 180]. So I have to do an extra step of converting negative angles to positive. I hope someone struggling with point rotation with negative or positive angles can use the following.

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
Related