Rotation d'un point autour d'un autre point (2D)


139

J'essaye de faire un jeu de cartes où les cartes se déploient. En ce moment, pour l'afficher, j'utilise l'API Allegro qui a une fonction:

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

donc avec cela je peux faire mon effet de fan facilement. Le problème est alors de savoir quelle carte se trouve sous la souris. Pour ce faire, j'ai pensé à faire un test de collision de polygones. Je ne sais tout simplement pas comment faire pivoter les 4 points sur la carte pour constituer le polygone. Je dois essentiellement faire la même opération qu'Allegro.

par exemple, les 4 points de la carte sont:

card.x

card.y

card.x + card.width

card.y + card.height

J'aurais besoin d'une fonction comme:

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

Merci

Réponses:


331

Soustrayez d'abord le point de pivot (cx,cy), puis faites-le pivoter, puis ajoutez à nouveau le point.

Non testé:

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
Excellente réponse. Pour mémoire, vous avez obtenu la rotation correcte du premier coup.
n.collins

@synchronizer exactement la même chose, utilisez simplement vos routines de soustraction / addition de points et votre fonction de matrice vectorielle * pour la rotation.
Nils Pipenbrinck

8
Cela pourrait être utile pour les imprudents de mentionner que sin et cos peuvent s'attendre à ce que l'angle soit exprimé en radians.
15ee8f99-57ff-4f92-890c-b56153

Ai-je raison de m'attendre à ce que des valeurs positives d' angle effectuent une rotation vers la droite (dans le sens des aiguilles d'une montre) et que fournir une valeur négative l'exécute vers la gauche (dans le sens inverse des aiguilles d'une montre)? Ou est-ce que le sens anti-horaire est une opération plus compliquée (c.-à-d. Calculer l'angle inverse puis tourner dans le sens horaire de cette quantité)? J'ai vu une tonne de pages donnant cette même formule, mais personne ne semble jamais jugé bon de parler de directionnalité par rapport aux valeurs d'entrée / sortie ...
NetXpert il y a

72

Si vous faites pivoter le point (px, py)autour du point (ox, oy)par l' angle thêta vous obtiendrez:

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

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

c'est un moyen simple de faire pivoter un point en 2D.


7
Vous devez effectuer une translation après la rotation. donc la solution serait: p'x + = ox
hAlE

57

Le système de coordonnées à l'écran est gaucher, c'est-à-dire que la coordonnée x augmente de gauche à droite et la coordonnée y augmente de haut en bas. L'origine, O (0, 0) est dans le coin supérieur gauche de l'écran.

entrez la description de l'image ici

Une rotation dans le sens des aiguilles d' une montre autour de l'origine d'un point de coordonnées (x, y) est donnée par les équations suivantes:

entrez la description de l'image ici

où (x ', y') sont les coordonnées du point après rotation et l'angle thêta, l'angle de rotation (doit être en radians, c'est-à-dire multiplié par: PI / 180).

Pour effectuer une rotation autour d'un point différent de l'origine O (0,0), disons le point A (a, b) (point de pivot). Tout d'abord, nous traduisons le point à faire pivoter, c'est-à-dire (x, y) vers l'origine, en soustrayant les coordonnées du point de pivot, (x - a, y - b). Ensuite, nous effectuons la rotation et obtenons les nouvelles coordonnées (x ', y') et enfin nous traduisons le point en arrière, en ajoutant les coordonnées du point de pivot aux nouvelles coordonnées (x '+ a, y' + b).

Suite à la description ci-dessus:

une rotation 2D en thêta degrés dans le sens horaire du point (x, y) autour du point (a, b) est:

En utilisant votre prototype de fonction: (x, y) -> (px, py); (a, b) -> (cx, cy); thêta -> angle:

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

Pour une rotation dans le sens des aiguilles d'une montre:

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

Pour une rotation anti-horaire:

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

Qu'est-ce que cet s?
TankorSmash

1
@TankorSmash c'est défini cic = cos(angle)
nycynik

2

C'est la réponse de Nils Pipenbrinck, mais implémentée en 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: Apparemment, je ne peux pas commenter, donc je suis obligé de le poster comme réponse ...

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.