【问题标题】:Calculating the angle between a line and the x-axis计算直线和 x 轴之间的角度
【发布时间】:2011-02-10 05:27:55
【问题描述】:

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

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

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

【问题讨论】:

  • 从技术上讲,您无法获得两个之间的角度。你可以得到两个 vectors 之间的角度。
  • 很确定他的意思是“两点之间绘制的线与水平轴之间的角度”
  • 对不起,让我改一下标题,如何获得这两点定义的线与穿过屏幕中心对象的水平通道之间的角度?

标签: java android graphics


【解决方案1】:

假设: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 所说, 采用“两点之间的角度”的想法没有很好的定义。

【讨论】:

  • 谢谢 Jim,无论我使用的是笛卡尔坐标还是极坐标,我怎么知道计算出的角度是基于穿过我的对象的水平线而不是屏幕顶部的水平线,从左上角的原点出来??
  • @kingrichard2005:由于 delta_x 和 delta_y 是相对于中心点(对象的位置)计算的,所以 theta 也将相对于同一点计算。
  • 如果 y 从上到下增加会有什么变化?
  • @Scorb 在 Y 从上到下或从下到上递增之间变化,相当于翻转 delta_y 计算中的符号。对于自上而下,您将使用我在编辑中添加的公式。
【解决方案2】:

我自己也需要类似的功能,所以在拉了很多头发之后,我想出了下面的功能

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

【讨论】:

    【解决方案3】:

    这里的一些答案试图解释top left0,0bottom 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;
    }
    

    【讨论】:

    • 刚刚用不同的 x 和 y 值进行了测试;这个答案会产生屏幕坐标的准确结果。
    • 如果结果
    • @Mike :在示例代码中,结果将是 -45 而不是 315 没有对负数的更正。这两个值都是正确的,但从记忆中我只想要正值和0
    • @Tigger 好的,我现在看到了 :) 谢谢
    【解决方案4】:

    在 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()))
        }
    

    【讨论】:

      【解决方案5】:

      “原点在屏幕的左上角,Y坐标向下增加,而X坐标像往常一样向右增加。我想我的问题是,我是否必须转换屏幕坐标在应用上述公式之前转换为笛卡尔坐标?”

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

      【讨论】:

        【解决方案6】:

        使用 pygame:

        dy = p1.y - p2.y
        dX = p2.x - p1.x
        
        rads = atan2(dy,dx)
        degs = degrees(rads)
        if degs < 0 :
           degs +=90
        

        对我有用

        【讨论】:

          【解决方案7】:
          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(&lt;=&gt; 0) -&gt; 45 -&gt; 90 -&gt; 135 -&gt; 180 -&gt; 225 -&gt; 270 -&gt; 315

          类似于我们drawArc时的角度

          【讨论】:

          • 一些 JavaScript 实现:function calcAngle(ax, ay, bx, by){var dx = bx - ax; var dy = by - ay; return Math.atan2(dy, dx) * 180 / Math.PI;}
          猜你喜欢
          • 2011-11-27
          • 2016-06-19
          • 1970-01-01
          • 1970-01-01
          • 2019-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-07
          相关资源
          最近更新 更多