简体   繁体   English

计算直线与 x 轴之间的角度

[英]Calculating the angle between a line and the x-axis

I'm currently developing a simple 2D game for Android.我目前正在为 Android 开发一个简单的 2D 游戏。 I have a stationary object that's situated in the center of the screen and I'm trying to get that object to rotate and point to the area on the screen that the user touches.我有一个位于屏幕中心的静止对象,我试图让该对象旋转并指向用户触摸的屏幕区域。 I have the constant coordinates that represent the center of the screen and I can get the coordinates of the point that the user taps on.我有代表屏幕中心的恒定坐标,我可以获得用户点击的点的坐标。 I'm using the formula outlined in this forum: How to get angle between two points?我正在使用本论坛中概述的公式: 如何获得两点之间的角度?

  • It says as follows "If you want the the angle between the line defined by these two points and the horizontal axis:它说如下“如果你想要这两个点定义的线与水平轴之间的角度:

     double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
  • I implemented this, but I think the fact the I'm working in screen coordinates is causing a miscalculation, since the Y-coordinate is reversed.我实现了这个,但我认为我在屏幕坐标中工作的事实导致计算错误,因为 Y 坐标是相反的。 I'm not sure if this is the right way to go about it, any other thoughts or suggestions are appreciated.我不确定这是否是正确的方法,任何其他想法或建议表示赞赏。

Assumptions: x is the horizontal axis, and increases when moving from left to right.假设: x为水平轴,从左向右移动时增加。 y is the vertical axis, and increases from bottom to top. y是纵轴,从下往上递增。 (touch_x, touch_y) is the point selected by the user. (touch_x, touch_y)是用户选择的点。 (center_x, center_y) is the point at the center of the screen. (center_x, center_y)是屏幕中心的点。 theta is measured counter-clockwise from the +x axis. theta是从+x轴逆时针测量的。 Then:然后:

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

Edit : you mentioned in a comment that y increases from top to bottom.编辑:您在评论中提到 y 从上到下增加。 In that case,在这种情况下,

delta_y = center_y - touch_y

But it would be more correct to describe this as expressing (touch_x, touch_y) in polar coordinates relative to (center_x, center_y) .但将其描述为在相对于(center_x, center_y)的极坐标中表达(touch_x, touch_y)会更正确。 As ChrisF mentioned, the idea of taking an "angle between two points" is not well defined.正如 ChrisF 所提到的,“两点之间的角度”的概念并没有得到很好的定义。

Had a need for similar functionality myself, so after much hair pulling I came up with the function below我自己也需要类似的功能,所以在拉了很多头发之后,我想出了下面的功能

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

A few answers here have tried to explain the "screen" issue where top left is 0,0 and bottom right is (positive) screen width, screen height .这里的一些答案试图解释“屏幕”问题, top left0,0bottom right是(正) screen width, screen height Most grids have the Y axis as positive above X not below.大多数网格的Y轴在X上方而不是下方为正。

The following method will work with screen values instead of "grid" values.以下方法将使用屏幕值而不是“网格”值。 The only difference to the excepted answer is the Y values are inverted.与例外答案的唯一区别是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;
}

in android i did this using kotlin:在 android 中,我使用 kotlin 做到了这一点:

private fun angleBetweenPoints(a: PointF, b: PointF): Double {
        val deltaY = abs(b.y - a.y)
        val deltaX = abs(b.x - a.x)
        return Math.toDegrees(atan2(deltaY.toDouble(), deltaX.toDouble()))
    }
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()
}

This function will return value like此函数将返回值,如

If we + 180 to the return value then we will get the value from right to left like如果我们+ 180到返回值,那么我们将从右到左获取值,如

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

similar to the angle when we drawArc类似于我们drawArc时的角度

"the origin is at the top-left of the screen and the Y-Coordinate increases going down, while the X-Coordinate increases to the right like normal. I guess my question becomes, do I have to convert the screen coordinates to Cartesian coordinates before applying the above formula?" “原点在屏幕的左上角,Y坐标向下增加,而X坐标像往常一样向右增加。我想我的问题是,我是否必须将屏幕坐标转换为笛卡尔坐标在应用上述公式之前?”

If you were calculating the angle using Cartesian coordinates, and both points were in quadrant 1 (where x>0 and y>0), the situation would be identical to screen pixel coordinates (except for the upside-down-Y thing. If you negate Y to get it right-side up, it becomes quadrant 4...).如果您使用笛卡尔坐标计算角度,并且两个点都在象限 1(其中 x>0 和 y>0),则情况将与屏幕像素坐标相同(除了颠倒的 Y 事物。如果您否定 Y 使其正面朝上,它变成象限 4...)。 Converting screen pixel coordinates to Cartesian doesnt really change the angle.将屏幕像素坐标转换为笛卡尔坐标并不会真正改变角度。

with pygame:使用 pygame:

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

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

it work for me它对我有用

If you wanto get slope as radian -> m = math.atan2((jy-iy),(jx-ix))如果您希望将斜率设为弧度 -> m = math.atan2((jy-iy),(jx-ix))

and degree ---> m = math.atan2((jy-iy),(jx-ix))*180/math.pi和度---> m = math.atan2((jy-iy),(jx-ix))*180/math.pi

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM