C++中atan()与atan2()的区别和用法

区别

atan(x)函数接收一个参数。参数类型可参考下列函数声明。

double atan (double x);
float atan (float x);
long double atan (long double x);
double atan (T x);           // additional overloads for integral types

若有一个坐标A(a,b),则函数参数x=b/a。
atan(x)函数返回以弧度为单位的角度,范围为[-pi/2,+pi/2],注意是包含-pi/2和+pi/2的。该角度为A点和原点的连线与X轴正方向之间的夹角。上方夹角为正,下方夹角为负。由此可以看出,atan()函数只能区分一象限和四象限的点。取一象限和三象限任意一点Ai(ai,bi)计算x=bi/ai,x均为正值。对于二象限和四象限则均为负值。
atan参考
atan2(y,x)函数接收两个参数,即一个坐标值。参数类型可参考下列函数声明。

double atan2 (double y     , double x);
float atan2 (float y      , float x);
long double atan2 (long double y, long double x);
double atan2 (Type1 y      , Type2 x);       // additional overloads

atan2(x)函数返回以弧度为单位的角度,范围为[-pi,+pi],注意是包含-pi和+pi的。函数内部考虑了参数x,y 的符号。所以可以区分坐标点在哪个象限。

atan2参考

使用示例

static double
normalize(double z)
{
  return atan2(sin(z),cos(z));
}

上述代码实现了不管输入多大的角度值(以弧度为单位),输出均落在[-pi,+pi]里。

static double
angle_diff(double a, double b)
{
  double d1, d2;
  a = normalize(a);
  b = normalize(b);
  d1 = a-b;
  d2 = 2*M_PI - fabs(d1);
  if(d1 > 0)
    d2 *= -1.0;
  if(fabs(d1) < fabs(d2))
    return(d1);
  else
    return(d2);
}

上述代码返回a,b之间的夹角,并且返回值总是落在[-pi,+pi]里。总是取从a到b夹角小的那部分,如果从a到b为顺时针旋转返回正值,反之返回负值。

参考文章:
What is the difference between atan and atan2 in C++?

关注公众号《首飞》回复“机器人”获取精心推荐的C/C++,Python,Docker,Qt,ROS1/2,机器人学等机器人行业常用技术资料。

以下是一个使用白塞尔方法进行大地主题反算的 C++ 代码示例: ```c++ #include <iostream> #include <cmath> #define PI 3.14159265358979323846 #define a 6378137.0 #define b 6356752.3142 #define f (a - b) / a #define e sqrt(2 * f - pow(f, 2)) using namespace std; double rad2deg(double rad) { return rad / PI * 180.0; } double deg2rad(double deg) { return deg * PI / 180.0; } double calcM(double lat) { double W = sqrt(1 - pow(e * sin(lat), 2)); return a * (1 - pow(e, 2)) / pow(W, 3); } double calcN(double lat) { double W = sqrt(1 - pow(e * sin(lat), 2)); return a / W; } double calcT(double lat) { return pow(tan(lat), 2); } double calcC(double lat) { double W = sqrt(1 - pow(e * sin(lat), 2)); return pow(e * cos(lat) / W, 2); } double calcA(double lat) { double W = sqrt(1 - pow(e * sin(lat), 2)); return (a / W) * (1 - pow(e, 2)) / pow(W, 2); } double calcS(double lat1, double lon1, double lat2, double lon2) { double dx = lon2 - lon1; double dy = lat2 - lat1; double lat1_rad = deg2rad(lat1); double lat2_rad = deg2rad(lat2); double dx_rad = deg2rad(dx); double N1 = calcN(lat1_rad); double M1 = calcM(lat1_rad); double T1 = calcT(lat1_rad); double C1 = calcC(lat1_rad); double A1 = calcA(lat1_rad); double W1 = sqrt(1 - pow(e * sin(lat1_rad), 2)); double cos_lat1 = cos(lat1_rad); double sin_lat1 = sin(lat1_rad); double sin2_lat1 = pow(sin_lat1, 2); double cos2_lat1 = pow(cos_lat1, 2); double W2 = sqrt(1 - pow(e * sin(lat2_rad), 2)); double cos_lat2 = cos(lat2_rad); double sin_lat2 = sin(lat2_rad); double sin2_lat2 = pow(sin_lat2, 2); double cos2_lat2 = pow(cos_lat2, 2); double Wx = W2 - W1; double Wx2 = pow(Wx, 2); double Wy = (cos_lat2 * dx_rad); double Wy2 = pow(Wy, 2); double M2 = calcM(lat2_rad); double N2 = calcN(lat2_rad); double T2 = calcT(lat2_rad); double C2 = calcC(lat2_rad); double A2 = calcA(lat2_rad); double M = (M1 + M2) / 2.0; double mx = dx_rad * cos_lat1 * M; double my = dy * M; double m = sqrt(pow(mx, 2) + pow(my, 2)); double latm = lat1_rad + (dy - (T1 + C1) * (pow(dy, 3) / 6.0) + (5.0 - 18.0 * T1 + pow(T1, 2) + 72.0 * C1 - 58.0 * A1) * (pow(dy, 5) / 120.0)) / M; double Wm = sqrt(1 - pow(e * sin(latm), 2)); double Nm = a / Wm; double Tm = pow(tan(latm), 2); double Cm = pow(e * cos(latm) / Wm, 2); double Am = (a / Wm) * (1 - pow(e, 2)) / pow(Wm, 2); double theta = atan(mx / my); if (my < 0) { theta += PI; } double s = m * cos(theta) + (Wx2 - Wy2) / (2.0 * Nm); return s; } double calcAzimuth(double lat1, double lon1, double lat2, double lon2) { double lat1_rad = deg2rad(lat1); double lat2_rad = deg2rad(lat2); double dLon_rad = deg2rad(lon2 - lon1); double y = sin(dLon_rad) * cos(lat2_rad); double x = cos(lat1_rad) * sin(lat2_rad) - sin(lat1_rad) * cos(lat2_rad) * cos(dLon_rad); double azimuth_rad = atan2(y, x); return rad2deg(azimuth_rad); } int main() { double lat1 = 22.331; double lon1 = 114.264; double lat2 = 22.351; double lon2 = 114.162; double s = calcS(lat1, lon1, lat2, lon2); double azimuth = calcAzimuth(lat1, lon1, lat2, lon2); cout << "S = " << s << " m" << endl; cout << "Azimuth = " << azimuth << " deg" << endl; return 0; } ``` 在这个示例,我们定义了一些常量,例如地球椭球体的长半轴 `a`、短半轴 `b`、扁率 `f` 和第一偏心率 `e`。然后,我们实现了一些函数来计算需要用到的各个参数,例如子午线曲率半径 `M`、卯酉圈曲率半径 `N`、子午线弧长公式的参数 `T`、`C` 和 `A`,以及两点之间的大地线长度 `S` 和方位角 `azimuth`。最后,我们在 `main` 函数调用这些函数来计算两点之间的大地线长度和方位角,并将它们输出到控制台上。 需要注意的是,在实现白塞尔方法时,需要将角度转换为弧度计算。在本示例,我们使用了 `deg2rad` 和 `rad2deg` 两个函数来进行角度和弧度的转换。同时,为了方便起见,我们将计算经常用到的参数都定义为常量,以免在多处使用时出现错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

首飞爱玩机器人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值