计算由两点定义的直线之间的角度

时间:2010-04-20 16:12:06

标签: java android graphics

我目前正在为Android开发一款简单的2D游戏。我有一个静止的物体位于屏幕的中心,我试图让该物体旋转并指向屏幕上用户接触的区域。我有恒定的坐标代表屏幕的中心,我可以得到用户点击的点的坐标。我正在使用此论坛中概述的公式:How to get angle between two points?

  • 如下所示“如果你想要这两个点定义的直线与水平轴之间的角度:

    double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
    
  • 我实现了这一点,但我认为我在屏幕坐标中工作的事实导致错误计算,因为Y坐标是反转的。我不确定这是否是正确的方法,任何其他想法或建议都表示赞赏。

7 个答案:

答案 0 :(得分:57)

假设: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所说, 采取“两点之间的角度”的想法尚未明确界定。

答案 1 :(得分:29)

我自己需要类似的功能,所以经过多次拔毛我想出了下面的功能

/**
 * 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);
}

答案 2 :(得分:15)

这里的一些答案试图解释&#34;屏幕&#34; top left0,0bottom right为(正)screen width, screen height的问题。大多数网格的Y轴都高于X以下的正值。

以下方法适用于屏幕值,而不是&#34; grid&#34;值。与例外答案的唯一区别是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;
}

答案 3 :(得分:1)

“原点位于屏幕的左上角,Y坐标增加下降,而X坐标则正常增加。我想我的问题变成了,我是否需要转换屏幕坐标在应用上述公式之前的笛卡尔坐标?“

如果使用笛卡尔坐标计算角度,并且两个点都在象限1(其中x> 0且y> 0),则情况与屏幕像素坐标相同(除了颠倒的Y事物)如果你否定Y以使其正确向上,它就会成为象限4 ...)。将屏幕像素坐标转换为笛卡尔并不会真正改变角度。

答案 4 :(得分:0)

使用pygame:

dy = p1.y - p2.y
dX = p2.x - p1.x

rads = atan2(dy,dx)
degs = degrees(rads)
if degs < 0 :
   degs +=90

对我有用

答案 5 :(得分:0)

在android中,我使用Kotlin做到了这一点:

override func willMove(toParent parent: UIViewController?) {
        navigationController?.navigationBar.prefersLargeTitles = true
}

答案 6 :(得分:0)

fun calculateAngle(
    touchX: Float,
    touchY: Float,
    centerX: Float,
    centerY: Float
): Float {
    val deltaX = centerX - touchX
    val deltaY = centerY - touchY
    return Math.toDegrees(atan2(deltaY.toDouble(), deltaX.toDouble())).toFloat()
}

这个函数会返回类似的值

如果我们+ 180到返回值,那么我们将从从右到左获取值,就像

360(<=> 0) -> 45 -> 90 -> 135 -> 180 -> 225 -> 270 -> 315

类似于我们drawArc时的角度