web-dev-qa-db-ja.com

2点で定義された線の間の角度の計算

現在、Android用のシンプルな2Dゲームを開発しています。画面の中央に静止したオブジェクトがあり、そのオブジェクトを回転させて、ユーザーがタッチする画面上の領域をポイントしようとしています。画面の中心を表す一定の座標があり、ユーザーがタップしたポイントの座標を取得できます。このフォーラムで概説されている式を使用しています: 2点間の角度を取得する方法?

  • 「これらの2点で定義される線と水平軸の間の角度が必要な場合:

    double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
    
  • これを実装しましたが、Y座標が逆になっているため、画面座標で作業しているという事実が誤った計算を引き起こしていると思います。これが正しい方法であるかどうかはわかりませんが、他の考えや提案は歓迎します。

36
kingrichard2005

仮定:xは水平軸であり、左から右に移動すると増加します。 yは垂直軸であり、下から上に向かって増加します。 (touch_x, touch_y)は、ユーザーが選択したポイントです。 (center_x, center_y)は、画面の中央の点です。 thetaは、+x軸から反時計回りに測定されます。次に:

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

編集:コメントで、yが上から下に向かって増加することを述べました。その場合、

delta_y = center_y - touch_y

しかし、これは(touch_x, touch_y)を基準とした極座標で(center_x, center_y)を表すものとして記述する方が正しいでしょう。 ChrisFが述べたように、「2点間の角度」をとるという考えは十分に定義されていません。

60
Jim Lewis

自分で同様の機能が必要だったので、多くの髪を引っ張った後、以下の機能を思いつきました

/**
 * 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

ここでのいくつかの回答は、top left0,0およびbottom rightは(正)screen width, screen height。ほとんどのグリッドでは、Y軸が下ではなくXの上に正としてあります。

次のメソッドは、「グリッド」値の代わりに画面値を使用します。例外の答えとの唯一の違いは、Y値が反転していることです。

/**
 * 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

「原点は画面の左上にあり、Y座標は下に向かって増加し、X座標は通常のように右に増加します。私の質問は、画面座標をデカルト座標に変換する必要があると思います上記の式を適用する前に?」

デカルト座標を使用して角度を計算し、両方のポイントが象限1(x> 0およびy> 0)にある場合、状況はスクリーンピクセル座標と同じになります(上下逆のYを除く)。 Yを無効にして、正しい状態に戻すと、象限4 ...になります。画面のピクセル座標をデカルト座標に変換しても、実際には角度は変わりません。

1
Golfcabalist