经纬度度分秒转换、距离计算、墨卡托投影及平面直角坐标转换

网图

一、度分秒转换

度转换为度分秒、度分秒转换为度示例如下:

// 度转换为度分秒
std::string decimalToDMS(double decimalDeg) {
    int degrees = static_cast<int>(decimalDeg);
    double minutesSeconds = (decimalDeg - degrees) * 60;
    int minutes = static_cast<int>(minutesSeconds);
    double seconds = (minutesSeconds - minutes) * 60;
    return std::to_string(degrees) + "°" + std::to_string(minutes) + "'" + std::to_string(seconds) + "\"";
}

// 度分秒转换为度
double DMSToDecimal(const std::string& dms) {
    size_t degreePos = dms.find("°");
    size_t minutePos = dms.find("'");
    size_t secondPos = dms.find("\"");

    int degrees = std::stoi(dms.substr(0, degreePos));
    int minutes = std::stoi(dms.substr(degreePos + 1, minutePos - degreePos - 1));
    double seconds = std::stod(dms.substr(minutePos + 1, secondPos - minutePos - 1));

    double decimalDeg = degrees + (minutes / 60.0) + (seconds / 3600.0);
    return decimalDeg;
}

二、经纬度间距离计算

通用计算方法为Haversine公式,转换为代码如下:

double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
    double earthRadius = 6371.0; // 地球半径,单位:千米

    // 将经纬度转换为弧度
    double dLat = (lat2 - lat1) * M_PI / 180.0;
    double dLon = (lon2 - lon1) * M_PI / 180.0;

    // 应用Haversine公式计算直线距离
    double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1 * M_PI / 180.0) * cos(lat2 * M_PI / 180.0) * sin(dLon / 2) * sin(dLon / 2);
    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    double distance = earthRadius * c;

    return distance;
}

三、经纬度墨卡托投影

地理投影方法之一,可以将地球表面的经纬度坐标投影到平面坐标系上
原理参考:https://dandelioncloud.cn/article/details/1573648470961778689
转换为代码如下:

void mercatorProjection(double lat, double lon, double& x, double& y) {
    const double R = 6378137.0; // 地球半径,单位:米

    double lat_rad = lat * M_PI / 180.0; // 将纬度转换为弧度
    double lon_rad = lon * M_PI / 180.0; // 将经度转换为弧度

    x = R * lon_rad; // 经度直接转换为 X 坐标
    y = R * log(tan(M_PI / 4 + lat_rad / 2)); // 纬度转换为 Y 坐标
}

缺点:在墨卡托投影中,纬度值大致等于真实地球上的距离,而经度值仅作线性缩放。这种投影方法适用于大范围的地理数据处理。

四、经纬度平面直角坐标转换

假设地球是一个完美的球体,并将经纬度转换为直角坐标系中的X和Y坐标。然后,根据输入的目标航向角对坐标进行旋转,以得到参照物相对于目标的坐标偏移。
转换为代码如下:

const double EARTH_RADIUS = 6378137.0; // 地球半径,单位:米

struct Coordinate {
    double x; // 参照物在目标坐标系中的X坐标
    double y; // 参照物在目标坐标系中的Y坐标
};

Coordinate calculateCoordinates(double masterLatitude, double masterLongitude, double slaveLatitude, double slaveLongitude, double heading) {
    double masterRadLat = masterLatitude * M_PI / 180;
    double masterRadLon = masterLongitude * M_PI / 180;
    double slaveRadLat = slaveLatitude * M_PI / 180;
    double slaveRadLon = slaveLongitude * M_PI / 180;

    double latDifference = slaveRadLat - masterRadLat;
    double lonDifference = slaveRadLon - masterRadLon;

	//乘以 EARTH_RADIUS 来计算参照物相对于目标的东西方向(水平方向)的偏移量,由于纬度变化会导致经度方向上的弧长缩短,所以需要乘以 cos(masterRadLat)将纬度的影响纳入考虑,从而得到更准确的结果
    double dx = EARTH_RADIUS * lonDifference * std::cos(masterRadLat);
	//乘以 EARTH_RADIUS 来计算参照物相对于目标的南北方向(垂直方向)的偏移量
    double dy = EARTH_RADIUS * latDifference;

    // 考虑目标航向角,heading 为正,对坐标进行逆时针旋转
    double radHeading = heading * M_PI / 180;
	double rotatedX = dx * std::cos(radHeading) - dy * std::sin(radHeading);
    double rotatedY = dx * std::sin(radHeading) + dy * std::cos(radHeading);

	//  若顺时针旋转
	//double rotatedX = dx * std::cos(radHeading) + dy * std::sin(radHeading);
    //double rotatedY = -dx * std::sin(radHeading) + dy * std::cos(radHeading);
	
    Coordinate coord;
    coord.x = rotatedX;
    coord.y = rotatedY;

    return coord;
}

缺点:实际运用需对参照物运动模型进行预测和做滤波处理。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值