web-dev-qa-db-fra.com

Calcul de l'angle entre la ligne définie par deux points

Je développe actuellement un jeu 2D simple pour Android. J'ai un objet stationnaire situé au centre de l'écran et j'essaie de faire pivoter cet objet et de pointer vers la zone de l'écran que l'utilisateur touche. J'ai les coordonnées constantes qui représentent le centre de l'écran et je peux obtenir les coordonnées du point sur lequel l'utilisateur tape. J'utilise la formule décrite dans ce forum: Comment obtenir un angle entre deux points?

  • Il dit comme suit "Si vous voulez l'angle entre la ligne définie par ces deux points et l'axe horizontal:

    double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
    
  • J'ai implémenté cela, mais je pense que le fait que je travaille sur les coordonnées d'écran provoque une erreur de calcul, car la coordonnée Y est inversée. Je ne sais pas si c'est la bonne façon de procéder, toute autre pensée ou suggestion est appréciée.

36
kingrichard2005

Hypothèses: x est l'axe horizontal et augmente lorsque vous vous déplacez de gauche à droite. y est l'axe vertical et augmente de bas en haut. (touch_x, touch_y) est le point sélectionné par l'utilisateur. (center_x, center_y) est le point au centre de l'écran. theta est mesuré dans le sens antihoraire à partir de +x axe. Ensuite:

delta_x = touch_x - center_x
delta_y = touch_y - center_y
theta_radians = atan2(delta_y, delta_x)

Edit: vous avez mentionné dans un commentaire que y augmente de haut en bas. Dans ce cas,

delta_y = center_y - touch_y

Mais il serait plus correct de décrire cela comme exprimant (touch_x, touch_y) en coordonnées polaires par rapport à (center_x, center_y). Comme ChrisF l'a mentionné, l'idée de prendre un "angle entre deux points" n'est pas bien définie.

60
Jim Lewis

J'avais moi-même besoin de fonctionnalités similaires, donc après avoir tiré beaucoup de cheveux, j'ai trouvé la fonction ci-dessous

/**
 * Fetches angle relative to screen centre point
 * where 3 O'Clock is 0 and 12 O'Clock is 270 degrees
 * 
 * @param screenPoint
 * @return angle in degress from 0-360.
 */
public double getAngle(Point screenPoint) {
    double dx = screenPoint.getX() - mCentreX;
    // Minus to correct for coord re-mapping
    double dy = -(screenPoint.getY() - mCentreY);

    double inRads = Math.atan2(dy, dx);

    // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12 O'clock
    if (inRads < 0)
        inRads = Math.abs(inRads);
    else
        inRads = 2 * Math.PI - inRads;

    return Math.toDegrees(inRads);
}
29
Dave Discoid

Quelques réponses ici ont tenté d'expliquer le problème "d'écran" où top left est 0,0 et bottom right est (positif) screen width, screen height. La plupart des grilles ont l'axe Y positif au-dessus de X et non en dessous.

La méthode suivante fonctionnera avec des valeurs d'écran au lieu de valeurs de "grille". La seule différence avec la réponse exceptée est que les valeurs Y sont inversées.

/**
 * Work out the angle from the x horizontal winding anti-clockwise 
 * in screen space. 
 * 
 * The value returned from the following should be 315. 
 * <pre>
 * x,y -------------
 *     |  1,1
 *     |    \
 *     |     \
 *     |     2,2
 * </pre>
 * @param p1
 * @param p2
 * @return - a double from 0 to 360
 */
public static double angleOf(PointF p1, PointF p2) {
    // NOTE: Remember that most math has the Y axis as positive above the X.
    // However, for screens we have Y as positive below. For this reason, 
    // the Y values are inverted to get the expected results.
    final double deltaY = (p1.y - p2.y);
    final double deltaX = (p2.x - p1.x);
    final double result = Math.toDegrees(Math.atan2(deltaY, deltaX)); 
    return (result < 0) ? (360d + result) : result;
}
17
Tigger

"L'origine est en haut à gauche de l'écran et la coordonnée Y augmente en descendant, tandis que la coordonnée X augmente vers la droite comme d'habitude. Je suppose que ma question devient, dois-je convertir les coordonnées de l'écran en coordonnées cartésiennes avant d'appliquer la formule ci-dessus? "

Si vous calculiez l'angle à l'aide des coordonnées cartésiennes et que les deux points se trouvaient dans le quadrant 1 (où x> 0 et y> 0), la situation serait identique aux coordonnées des pixels de l'écran (sauf pour la chose à l'envers-Y. Si vous nie Y pour le placer dans le bon sens, il devient le quadrant 4 ...). La conversion des coordonnées des pixels de l'écran en cartésien ne change pas vraiment l'angle.

1
Golfcabalist