大地坐标系到站心坐标系(ENU)坐标转换(提供QT和JAVA源码)

在做两个坐标系转换的时候,谷歌好长时间C++相关的代码资料,查找到两个转换的代码,但是结果都不对,故记录本次的坐标转换。

测试结果:

 QT源码:

WGS84ToENU.h

#ifndef WGS84TOENU_H
#define WGS84TOENU_H

#include <QMainWindow>
#include<QDateTime>

class WGS84ToENU
{
public:
    WGS84ToENU();
    double* wgs84ToEcef(double lat, double lon, double h);
    double* ecefToEnu(double x, double y, double z, double lat, double lng, double height);
    double DMS_RAD(double DMS);

};

#endif // WGS84TOENU_H
WGS84ToENU.cpp

#include "wgs84toenu.h"
#include<QtMath>
#include<QDebug>
#define a   6378137
#define b   6356752.3142//b为椭球的短半轴:a=6356.7523141km
#define RAD 57.295779 //一弧度约为57.295779°
WGS84ToENU::WGS84ToENU()
{

}
double WGS84ToENU::DMS_RAD(double DMS)
{
    double Rad=0.00;
    Rad=DMS/RAD;
    qDebug()<<"Rad"<<QString::number(Rad,'f',9);
    return Rad;
}
double* WGS84ToENU::wgs84ToEcef(double lat, double lon, double h)
{
            double f = (a - b) / a;
            double e_sq = f * (2 - f);
            double lamb = this->DMS_RAD(lat);

            double phi = this->DMS_RAD(lon);
            double s = sin(lamb);
            double N = a / sqrt(1 - e_sq * s * s);

            double sin_lambda = sin(lamb);
            double cos_lambda = cos(lamb);
            double sin_phi = sin(phi);
            double cos_phi = cos(phi);

            double x = (h + N) * cos_lambda * cos_phi;
            double y = (h + N) * cos_lambda * sin_phi;
            double z = (h + (1 - e_sq) * N) * sin_lambda;

            double *returnArr=new double[3];
            returnArr[0]=x;
            returnArr[1]=y;
            returnArr[2]=z;
            return returnArr;
}

 double* WGS84ToENU::ecefToEnu(double x, double y, double z, double lat, double lng, double height)
 {
     double f = (a - b) / a;
             double e_sq = f * (2 - f);
             double lamb = this->DMS_RAD(lat);
             double phi = this->DMS_RAD(lng);
             double s =sin(lamb);
             double N = a / sqrt(1 - e_sq * s * s);
             double sin_lambda = sin(lamb);
             double cos_lambda = cos(lamb);
             double sin_phi = sin(phi);
             double cos_phi = cos(phi);

             double x0 = (height + N) * cos_lambda * cos_phi;
             double y0 = (height + N) * cos_lambda * sin_phi;
             double z0 = (height + (1 - e_sq) * N) * sin_lambda;

             double xd = x - x0;
             double yd = y - y0;
             double zd = z - z0;
             double t = -cos_phi * xd - sin_phi * yd;
             double xEast = -sin_phi * xd + cos_phi * yd;
             double yNorth = t * sin_lambda + cos_lambda * zd;
             double zUp = cos_lambda * cos_phi * xd + cos_lambda * sin_phi * yd + sin_lambda * zd;
             double *returnArrAndNEU=new double[3];
                    returnArrAndNEU[0]=xEast;
                    returnArrAndNEU[1]=yNorth;
                    returnArrAndNEU[2]=zUp;
             qDebug()<<"xEast"<<QString::number(xEast,'f',9);
             qDebug()<<"yNorth"<<QString::number(yNorth,'f',9);
             qDebug()<<"zUp"<<QString::number(zUp,'f',9);
             return returnArrAndNEU;
 }

 QT测试代码(主函数代码):

 WGS84ToENU *wgs84ToEnu=new WGS84ToENU();
    double* arr1 = wgs84ToEnu->wgs84ToEcef(31.48999455, 121.9440825, 10.800000000);//此处经纬度是需要比对的偏移经纬度
    qDebug()<<"arr1[0]"<<QString::number(arr1[0],'f',9);
    qDebug()<<"arr1[1]"<<QString::number(arr1[1],'f',9);
    qDebug()<<"arr1[2]"<<QString::number(arr1[2],'f',9);
    double* xyz=wgs84ToEnu->ecefToEnu(arr1[0],arr1[1], arr1[2],31.489996667, 121.94408167,  12.700000000);
     qDebug()<<"result1x"<<QString::number(xyz[0],'f',9);
     qDebug()<<"result1y"<<QString::number(xyz[1],'f',9);
     qDebug()<<"result1z"<<QString::number(xyz[2],'f',9);

 JAVA源码:

public class testEcef {
	public static double[] wgs84ToEcef(double lat, double lon, double h) {
		double a = 6378137;
		double b = 6356752.3142;
		double f = (a - b) / a;
		double e_sq = f * (2 - f);
		double lamb = Math.toRadians(lat);
		double phi = Math.toRadians(lon);
		System.out.println("lamb"+lamb);
		System.out.println("phi"+phi);
		double s = Math.sin(lamb);
		double N = a / Math.sqrt(1 - e_sq * s * s);

		double sin_lambda = Math.sin(lamb);
		double cos_lambda = Math.cos(lamb);
		double sin_phi = Math.sin(phi);
		double cos_phi = Math.cos(phi);

		double x = (h + N) * cos_lambda * cos_phi;
		double y = (h + N) * cos_lambda * sin_phi;
		double z = (h + (1 - e_sq) * N) * sin_lambda;
		return new double[]{x,y,z};
	}

	public static double[] ecefToEnu(double x, double y, double z, double lat, double lng, double height) {
		double a = 6378137;
		double b = 6356752.3142;
		double f = (a - b) / a;
		double e_sq = f * (2 - f);
		double lamb = Math.toRadians(lat);
		double phi = Math.toRadians(lng);
		System.out.println("lamb2"+lamb);
		System.out.println("phi2"+phi);
		double s = Math.sin(lamb);
		double N = a / Math.sqrt(1 - e_sq * s * s);
		double sin_lambda = Math.sin(lamb);
		double cos_lambda = Math.cos(lamb);
		double sin_phi = Math.sin(phi);
		double cos_phi = Math.cos(phi);

		double x0 = (height + N) * cos_lambda * cos_phi;
		double y0 = (height + N) * cos_lambda * sin_phi;
		double z0 = (height + (1 - e_sq) * N) * sin_lambda;

		double xd = x - x0;
		double yd = y - y0;
		double zd = z - z0;

		double t = -cos_phi * xd - sin_phi * yd;

		double xEast = -sin_phi * xd + cos_phi * yd;
		double yNorth = t * sin_lambda + cos_lambda * zd;
		double zUp = cos_lambda * cos_phi * xd + cos_lambda * sin_phi * yd + sin_lambda * zd;
		return new double[] { xEast, yNorth, zUp };
	}


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//gpggaH "10.800000000"10.8
		//gpslat "31.494067233"31.48999455
		//gpslon "121.947391683"121.9440825
		//gpggaH2 "12.700000000"12.7
		//gpslat2 "31.489996667"31.489996667
		//gpslon2 "121.947391667"121.94408167
		double[] arr1 = wgs84ToEcef(31.48999455, 121.9440825, 10.800000000);//此处经纬度是需要比对的偏移经纬度
		double[] xyz=ecefToEnu(arr1[0],arr1[1], arr1[2],31.489996667, 121.94408167,  12.700000000);//此处经纬度是站点经纬度
		System.out.println("xyz[0]"+xyz[0]);
		System.out.println("xyz[1]"+xyz[1]);
		System.out.println("xyz[2]"+xyz[2]);
	}

}

经过和MATLAB相关数据核对,结果完全一样。所以代码可以放心的尝试,如有问题请留言讨论

热门文章

暂无图片
编程学习 ·

『杭电1251』统计难题

Problem DescriptionIgnatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).Input输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师…
暂无图片
编程学习 ·

XTransfer欧美本地账户可以收哪些地区的币种?

很多人注册了XTransfer账户之后,开通了XTransfer欧美本地账户。本地收款账户有两个,一个是美元的开户行是纽约的Community Federal Savings Bank(CFSB),一个是欧元的开户行是英国的 Currency Cloud。欧美本地收款账户可以用于接收欧洲、美国的本地汇款,买家通过本地清算网…
暂无图片
编程学习 ·

05 Pandas(2)

# Author:Nimo_Dingimport pandas as pd import numpy as np from pandas import Series,DataFrame# 数据表的合并 df1=DataFrame({name:[ZhangFei,GuanYu,a,b,c],data1:range(5) }) df2=DataFrame({name:[ZhangFei,GuanYu,A,B,c],data2:range(5) }) print(\n1、基于指定列进行…
暂无图片
编程学习 ·

Spring——Bean scope

Spring framework 支持6个范围(scope),其中4个只能在用web-aware时才能使用。当然,你也可以创建自定义范围。singleton : spring默认就是singleton,即在注册该bean的时候,会把这个bean存储到单列bean缓存,以后对该bean的所有的后续请求和引用都会返回缓存中的这一个bean…
暂无图片
编程学习 ·

反射 枚举和lambda

1 反射(reflect) 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法. 对于任意 一个对象,都能够调用它的任意方法和属性. 既然能拿到那么,我们就可以修改部分类型信息. 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. 2 使用场景: 可…
暂无图片
编程学习 ·

qtdesigner-尝试连接数据库

参考教程:基于PyQt5的数据库可视化操作界面MainWindow:生成的一个类,下面有setupUi和retranslateUi两个方法。 接下来是登录操作。教程中用的是pymssql,我们用pyodbc,目测应该差不多。 import pyodbc cnxn = pyodbc.connect(DRIVER={SQL Server};SERVER=localhost;DATABASE…
暂无图片
编程学习 ·

80端口被占用怎么处理

以管理员权限运行c:\windows\system32\cmd.exeC:\WINDOWS\system32>net stop httpHTTP Service 服务已成功停止。C:\WINDOWS\system32>netstat -ano | findstr 0.0.0.0:80C:\WINDOWS\system32>sc config http start=disabled[SC] ChangeServiceConfig 成功即可
暂无图片
编程学习 ·

IM即时通讯哇呼--解析

哇呼“Chat”是一款包含android客户端/ios客户端/pc客户端/WEB客户端的即时通讯系统。是由闪电云自主研发,服务器端源码直接部署在客户主机。非任何第三方IM通讯平台! 为各行业门户网站和企事业单位提供“一站式”定制解决方案,打造一个稳定,安全,高效,可扩展的即时通信系…
暂无图片
编程学习 ·

直播带货平台开发公司哪家强?

直播带货正在我们的生活中大放异彩,直播带货的用户却日益增多,甚至成为了一种刚需,未来的发展必然一片光明,在各大商场店铺实时播放,与实体店销售员一样承担着重要的角色,它战胜了传统的广告,正昂首阔步向我们走来。直播的背后,也凸显出社会的进步与电子商务格局的变化…
暂无图片
编程学习 ·

小程序自定义导航栏

记录下大神写的导航栏组件源自:https://juejin.im/post/5d557e2e5188255af1619716小程序改组件的下载链接:https://github.com/lingxiaoyi/miniprograms-navigation-bar
暂无图片
编程学习 ·

Docker学习(三) swarm 与tutk集群

Docker Swarmdocker集群概念 群集是一组运行docker的设备组成,其中部分机器是集群管理机(Swarm Manager) ,其他的是工作机(Worker)。群集中的机器可以是物理机或虚拟机。加入群集后,它们被统称节点(Node)。 Docker Swarm是docker公司发布的一套用来管理docker集群的工…
暂无图片
编程学习 ·

Linux彻底卸载Nginx

本机环境:centos7使用yum安装的Nginx1.首先输入命令 ps -ef | grep nginx检查一下nginx服务是否在运行。[root@localhost /]# ps -ef |grep nginx root 3163 2643 0 14:08 tty1 00:00:00 man nginx root 5427 1 0 14:50 ? 00:00:00 nginx: m…
暂无图片
编程学习 ·

MyBatis 结构拆解

MyBatis 的执行流程大概可以拆分为如下几个部分:初始化配置解析 mybatis-config.xml 文件 根据 mybatis-config.xml 文件中的配置,依次解析 Mapper.xml 文件 将 Mapper.xml 与 接口 通过 xml 文件的 namespace 属性来进行绑定**【重点】**;该篇有介绍 XML 文件和 接口进行绑…
暂无图片
编程学习 ·

人工智能常用数据预处理

人工智能常用数据预处理一级目录正态化、标准化、归一化、正则化区别和作用 一级目录 1.读数据 2.合并训练和测试 2.填充空白数据 4.改变非数字为数字 5.去除无关数据 6.降为(合并相关数据) 7.正态化数据(碗圆) 正态化、标准化、归一化、正则化区别和作用 1.正态化归一化是…
暂无图片
编程学习 ·

在使用R和Rstdio的常见问题

在Rstdio里无法画图有两种方法:一是使用代码 dev.new() 新建一个绘图窗口(我觉得这个方法好,因为在我的plots窗口画出来的图比例是变形的);二是换一个系统缓存目录,详细教程可以自行在网上寻找。在R里无法安装包可以像上面的方法二一样,换个缓存目录,或者在缓存目录里找…
暂无图片
编程学习 ·

[TypeScript] - TypeScript官方文档学习笔记-接口-上(二)

前言 接口只是在语法层面限制写法,从而使部分语句写法不出现,本质是语法规范 接口 TypeScript中接口用来定义结构类型,出于类型检查需要 编译转换后接口消失,仅用于语法检查 普通对象传入: function printLabel(labeledObj: { label: string }) {console.log(labeledObj.l…