软件构造 Lab1 中的 P2 Turtle Graphics(MIT)是一个很有创意的任务,该任务需要我们获取已有的程序后,利用 Turtle Soup 按照要求画图,其中需要利用几何知识设计一些函数简化编程,最后可以发挥想象力进行 Personal Art。
其中 Problem 6 是比较难理解的一个部分,需要用到 Java 中的 Math.atan2 方法。
任务要求
该问题的 a 部分,calculateBearingToPoint 的功能是:
已知海龟位置和当前朝向角度,求出指向终点需要转动的角度。海龟的 0° 线是向上,只能顺时针旋转。例如,如果海龟在(0,1)朝向 30°,若要指向(0,0),它必须再转动 150°。
Math.atan2 方法
- 该方法以 x 轴正半轴为极轴,原点(0, 0)为极点,将指定的直角坐标(x, y)转换为极坐标(r, θ),并返回弧度 θ 。
- atan2 方法的语法为:Math.atan2(double y, double x)
- 坐标 x 和 y 表示二维平面中的点。
- atan2 方法是静态方法。因此,我们可以使用类名Math直接调用该方法。
解决方案
- 首先使用Math.atan2 方法计算两点之间的边与 x 轴正半轴所成的弧度 radian;
- 然后把弧度值 radian 转换成角度值 degree;
- degree 取相反数(海龟旋转的方向是顺时针,极坐标角度的旋转方向是逆时针);
- 再加上90°(海龟的 0° 线向上,坐标轴的 0° 线向右,从顺时针角度看中间少了 90°);
- 然后从上一步的计算结果中除去海龟当前朝向角度,也就是减去 currentBearing;
- 最后将角度调整到 0 - 360° 之间(正角度)。
public static double calculateBearingToPoint(double currentBearing, int currentX, int currentY,
int targetX, int targetY) {
double radian = Math.atan2(targetY - currentY, targetX - currentX);
double degree = radian * 180.0 / Math.PI; //弧度变角度
double bearing;
bearing = (90.0 - degree) - currentBearing;
return bearing < 0 ? bearing + 360.0 : bearing;
}
Math.atan 方法
既然有 atan2,就肯定有 atan1,所以我查阅了相关资料,对 atan 方法做了简单的了解。
Math.atan 方法接受一个参数,该参数是直线的斜率 k,返回的是该斜率对应的弧度值。而我们经常需要使用的是直线与 x 轴的夹角。
double radian = Math.atan(k);
double degree = radian *180 / Math.PI;
但是,对于不同的角度,直线的斜率可能相等(角度相差180度的倍数),因此 Math.atan 方法返回的值可能不唯一,容易产生错误,因此最好使用 Math.atan2 方法。