【物联网-ATGM336H-6N-22-定位芯片】
·
物联网-ATGM336H-6N-22-定位芯片
■ 经度维度
■ ATGM336H-6N 单北斗定位导航模块简介
单北斗定位导航模块用户手册
该系列模块产品基于中科微第六代SOC单北斗芯片AT6668B,支持北斗二号和北斗三号(B1I和B1C)信号。
ATGM336H-6N单北斗系列模块应用了全新的导航一体化SOC单芯片技术,可以满足高精度定位、高精度授时的应用


■ NMEA-0183 协议解析(NMEA4.1)
■ 帧格式形如:$aaccc,ddd,ddd,…,ddd*hh(CR)(LF)
1、“$”:帧命令起始位
2、aaccc:地址域,前两位为识别符(aa),后三位为语句名(ccc)
3、ddd…ddd:数据
4、“*”:校验和前缀(也可以作为语句数据结束的标志)
5、hh:校验和(check sum),$与*之间所有字符 ASCII 码的校验和(各字节做异或运算,得到校验和后,再转换 16 进制格式的 ASCII 字符)
6、(CR)(LF):帧结束,回车和换行符
■ 地址域-识别符(aa)表示(GPS/BD/GLONASS/多星联合定位)
(1)单GPS
$GPGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*50
(2)单BD
$BDGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*4
(3)单GLONASS
$GLGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*4
(4)多星联合定位
$GNGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*4
■ NMEA-0183 常用命令如表所示:

■ XXGGA GPS定位数据
数据详解:$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*xx<CR><LF>
$GPGGA:起始引导符及语句格式说明(本句为GPS定位数据);
<1> UTC 时间,格式为hhmmss.sss;
<2> 纬度,格式为ddmm.mmmm(第一位是零也将传送);
<3> 纬度半球,N 或S(北纬或南纬)
<4> 经度,格式为dddmm.mmmm(第一位零也将传送);
<5> 经度半球,E 或W(东经或西经)
<6> 定位质量指示,0=定位无效,1=定位有效;
<7>使用卫星数量,从00到12(第一个零也将传送)
<8>水平精确度,0.5到99.9
<9>天线离海平面的高度,-9999.9到9999.9米M指单位米
<10>大地水准面高度,-9999.9到9999.9米M指单位米
<11>差分GPS数据期限(RTCMSC-104),最后设立RTCM传送的秒数量
<12>差分参考基站标号,从0000到1023(首位0也将传送)。
解析内容:
第9,10 个字段,海平面高度和大地水准面高度,单位是米
GGA信息:UTC时分秒、经纬度、GPS状态、卫星数量、高程、差分延迟、基站号此字段主要表示时间、经纬度位置、解算状态、卫星颗数等相关信息,XX因模式的不同而不同
(1)单GPS
$GPGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*50
(2)单BD
$BDGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*4
(3)单GLONASS
$GLGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*4
(4)多星联合定位
$GNGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*4

■ XXGSA 当前卫星信息
GSA信息:模式、定位状态、
例:$GPGSA,A,3,01,20,19,13,,,,,,,,,40.4,24.4,32.2*0A
字段0:$GPGSA,语句ID,表明该语句为GPS DOP and Active Satellites(GSA)当前卫星信息
字段1:定位模式,A=自动手动2D/3D,M=手动2D/3D
字段2:定位类型,1=未定位,2=2D定位,3=3D定位
字段3:PRN码(伪随机噪声码),第1信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段4:PRN码(伪随机噪声码),第2信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段5:PRN码(伪随机噪声码),第3信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段6:PRN码(伪随机噪声码),第4信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段7:PRN码(伪随机噪声码),第5信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段8:PRN码(伪随机噪声码),第6信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段9:PRN码(伪随机噪声码),第7信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段10:PRN码(伪随机噪声码),第8信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段11:PRN码(伪随机噪声码),第9信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段12:PRN码(伪随机噪声码),第10信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段13:PRN码(伪随机噪声码),第11信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段14:PRN码(伪随机噪声码),第12信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段15:PDOP综合位置精度因子(0.5 - 99.9)
字段16:HDOP水平精度因子(0.5 - 99.9)
字段17:VDOP垂直精度因子(0.5 - 99.9)
字段18:校验值
用于解算卫星信息。
(1) 单GPS
$GPGSA,M,3,25,14,15,18,31,27,09,21,22,12,1.5,0.9,1.3*30
(2) 单BD
$BDGSA,M,3,141,143,144,146,147,148,149,150,2.7,1.7,2.2*2B
(3) 单GLONASS
$GLGSA,M,3,47,58,55,46,53,57,56,1.7,1.1,1.3*2D
(4) 多星联合定位
$GNGSA,M,3,27,03,16,21,06,19,31,13,23,1.0,0.6,0.822
$GNGSA,M,3,141,142,143,144,147,148,150,1.0,0.6,0.810
$GNGSA,M,3,47,56,55,46,53,44,57,1.0,0.6,0.829

■ XXVTG 地面速度信息
$GPVTG,<1>,T,<2>,M,<3>,N,<4>,K,<5>*hh
<1> 以正北为参考基准的地面航向(000~359度,前面的0也将被传输)
<2> 以磁北为参考基准的地面航向(000~359度,前面的0也将被传输)
<3> 地面速率(000.0~999.9节,前面的0也将被传输)
<4> 地面速率(0000.0~1851.8公里/小时,前面的0也将被传输)
<5> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效
■ XXGSV 可视卫星状态
GSA信息:卫星数量、编号、信噪比(信号强度)、
例:$GPGSV,2,1,08,06,33,240,45,10,36,074,47,16,21,078,44,17,36,313,42*78
标准格式: $GPGSV,(1),(2),(3),(4),(5),(6),(7),…(4),(5),(6),(7)*hh(CR)(LF)
各部分含义为:
(1)总的GSV语句电文数;2;
(2)当前GSV语句号:1;
(3)可视卫星总数:08;
(4)PRN码(伪随机噪声码) 也可以认为是卫星编号
(5)仰角(00~90度):33度;
(6)方位角(000~359度):240度;
(7)信噪比(00~99dB):45dB(后面依次为第10,16,17号卫星的信息); *总和校验域; hh 总和校验数:78; (CR)(LF)回车,换行。
注:每条语句最多包括四颗卫星的信息,每颗卫星的信息有四个数据项,即:
(4)-卫星号,(5)-仰角,(6)-方位角,(7)-信噪比。
例:
$GPGSV,3,1,10,24,82,023,40,05,62,285,32,01,62,123,00,17,59,229,28*70
每条语句包含四部分内容,例如:第一部分是“24,82,023,40”,第二部分是“05,62,285,32”等等。
每部分的第一个词为PRC,第二个词为卫星高程,跟着为方位角和信号强度。
这个语句里最重要的指标应该算是“信号躁声比(signal-to-noise ratio)”(以下简称为SNR)。
这个数值标示卫星信号的接收率。我们知道,卫星是以相同的强度发射信号,但是传播过程中难免会遇到诸如树和墙之类的 障碍物,这样就影响了信号的识别。
典型的SNR值在0到50之间,其中50表示非常好的信号。(SNR可以达到99)。
每条GSV语句最多可以显示4个可见卫星的信息,其他的卫星都会在下一条语句中输出显示。每种卫星系统都会单独显示,如下:GPS有3条GSV报文,北斗有2条GSV报文,GLONASS有3条GSV报文。
$GPGSV,3,1,09,19,46,206,41,16,55,015,43,31,24,120,37,06,82,060,4373
$GPGSV,3,2,09,27,82,183,45,21,15,061,33,23,47,268,43,03,72,228,44*72
$GPGSV,3,3,09,13,34,304,38,*49
$BDGSV,2,1,07,143,53,202,37,145,15,257,40,148,72,234,38,141,49,145,37*67
$BDGSV,2,2,07,151,24,048,41,150,70,327,38,147,77,113,39,*65
$GLGSV,3,1,09,47,07,193,46,43,46,101,50,59,28,309,45,49,28,305,43*68
$GLGSV,3,2,09,48,35,239,45,42,21,040,44,57,24,063,39,44,24,161,47*67
$GLGSV,3,3,09,58, 46,012,45,51

■ XXRMC 最小定位信息
GSA信息:解状态、经纬度、地面速度、地面航向角、UTC时间、位置、速度、时间等信息。
数据详解:$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC 时间,hhmmss(时分秒)格式
<2> 定位状态,A=有效定位,V=无效定位
<3>纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
<4> 纬度半球N(北半球)或S(南半球)
<5>经度dddmm.mmmm(度分)格式(前面的0也将被传输)
<6> 经度半球E(东经)或W(西经)
<7>地面速率(000.0~999.9节,前面的0也将被传输)
<8>地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输)
<9> UTC 日期,ddmmyy(日月年)格式
<10>磁偏角(000.0~180.0度,前面的0也将被传输)
<11> 磁偏角方向,E(东)或W(西)
<12>模式指示(仅NMEA01833.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
解析内容:
1.时间,这个是格林威治时间,是世界时间(UTC),我们需要把它转换成北京时间(BTC),BTC和UTC差了8个小时,要在这个时间基础上加8个小时。
2. 定位状态,在接收到有效数据前,这个位是‘V’,后面的数据都为空,接到有效数据后,这个位是‘A’,后面才开始有数据。
3. 纬度,我们需要把它转换成度分秒的格式,计算方法:如接收到的纬度是:4546.40891
4546.40891/100=45.4640891 可以直接读出45度,
4546.40891–45*100=46.40891, 可以直接读出46分
46.40891–46 =0.40891*60=24.5346 读出24秒, 所以纬度是:45度46分24秒。
4. 南北纬,这个位有两种值‘N’(北纬)和‘S’(南纬)
5. 经度的计算方法和纬度的计算方法一样
6. 东西经,这个位有两种值‘E’(东经)和‘W’(西经)
7.速率,这个速率值是海里/时,单位是节,要把它转换成千米/时,根据:1海里=1.85公里,把得到的速率乘以1.85。
8. 航向,指的是偏离正北的角度
9. 日期,这个日期是准确的,不需要转换
(1) 单GPS
$GPRMC,064457.90,A,3110.4691141,N,12123.2667676,E,0.157,63.0,300713,0.0,W,A05
(2) 单BDS
$BDRMC,064457.90,A,3110.4691241,N,12123.2667666,E,0.157,63.0,300713,0.0,W,A*05
(3) 单GLONASS
$GLRMC,064457.90,A,3110.4691141,N,12123.2667646,E,0.157,63.0,300713,0.0,W,A*05
(4) 双星或多星联合定位
$GNRMC,064401.65,A,3110.4706987,N,12123.2653375,E,0.604,243.2,300713,0.0,W,A*3E

$GNRMC,082443.000,A,2240.8299056,N,11349.6730027,E,1.08,271.40,210426,,,A,V*0D
$GNVTG,271.40,T,,M,1.08,N,2.00,K,A*28
$GNGGA,082443.000,2240.8299056,N,11349.6730027,E,1,07,2.7,73.24,M,0.00,M,,,3.5*4B
$GNGSA,A,3,05,15,29,,,,,,,,,,4.4,2.7,3.5,1*38
$GNGSA,A,3,,,,,,,,,,,,,4.4,2.7,3.5,2*31
$GNGSA,A,3,,,,,,,,,,,,,4.4,2.7,3.5,3*30
$GNGSA,A,3,02,03,21,31,,,,,,,,,4.4,2.7,3.5,4*37
$GNGSA,A,3,,,,,,,,,,,,,4.4,2.7,3.5,0*33
$GPGSV,2,1,05,05,54,312,36,15,30,209,37,19,17,148,10,20,52,186,,1*63
$GPGSV,2,2,05,29,21,320,37,1*5C
$GLGSV,1,1,00,1*78
$GAGSV,1,1,00,7*73
$BDGSV,2,1,08,02,44,241,30,03,64,189,34,06,,,28,09,,,28,1*71
$BDGSV,2,2,08,19,,,28,21,49,230,32,31,64,343,38,35,,,28,1*72
$GQGSV,1,1,00,1*65
$GNGLL,2240.8299056,N,11349.6730027,E,082443.000,A,A*4A
$GNGST,082443.000,3.7,,,,2.3,7.8,10.6*63
$GNZDA,082443.000,21,04,2026,00,00*40
$GNDHV,082443.000,0.56,0.476,0.291,-0.026,0.55,,,,,M*2E
$GPTXT,01,01,01,ANTENNA OK*35
000444.900,0.00,0.000,0.000,0.000,0.00,,,,,M*0F
$GPTXT,01,01,01,ANTENNA OK*35
■ NMEA数据格式
■ $PCAS00-设置保存配置指令
拓展指令只有当前上电有效,重启后恢复默认。如果想要配置一次永久生效,可使用该指令。
$PCAS00*01
■ $PCAS01-设置串口波特率
例如: $PCAS01,1*1D //9600bps

■ $PCAS02-设置定位数据输出的频率
例:$PCAS02,1000*2E //1000ms

■ $PCAS03-设置输出数据NMEA语句过滤
例:$PCAS03,0,0,0,0,1,0,0,0*03

■ 实例一:只选择RMC
uint8_t txBuffer[] = "$PCAS03,0,0,0,0,1,0,0,0*03\r\n"; (只选择RMC)
sAPI_UartWrite(SC_UART3, txBuffer, strlen((char*)txBuffer));
串口输出:
[2025-06-26 18:56:34.829]# RECV ASCII>
$BDRMC,,V,,,,,,,,,,N,V*38
$BDRMC,,V,,,,,,,,,,N,V*38
$BDRMC,,V,
■ $PCAS04-设置(GPS/BDS/GLONASS)工作模式
例:$PCAS04,3*1A(GPS、BDS混合定位)

■ $PCAS05- NMEA 协议类型选择
例:$PCAS05,1*19

■ $PCAS06-查询模块信息
例:$PCAS06,1*1A

■ $PCAS10-设置重启
例:$PCAS10,0*1C //热启动

■ $PCAS12-设置低功耗
可以通过拉低ON_OFF管脚来进入低功耗模式,有些模块暂不支持低功耗指令。
■ $PCAS15-配置是否接收系统中任何一颗卫星
例:
"$PCAS15,2,FFFFFFFF*37\r\n" //开启北斗的 1-32 号卫星
"$PCAS15,2,FFFFFFE0*42\r\n" //开启北斗的 6-32 号卫星, 北斗 1-5 号卫星关闭
"$PCAS15,4,FFFF*31\r\n" //开启SBAS的 1-16 号卫星, 即 PRN=120-135 $PCAS15,5,1F47, 开启 QZSS 的 1-5 号卫星, 即 PRN=193, 194, 195, 199, 197

■ NMEA 校验
NMEA 校验和是将从 $ 后第一个字符开始到 * 之前的所有字符进行异或运算得到的值
■ NMEA 校验计算代码
#include <stdio.h>
#include <string.h>
// 计算 NMEA 校验和
unsigned char nmea_checksum(const char *sentence) {
unsigned char checksum = 0;
// 查找 '$' 和 '*' 的位置
const char *start = strchr(sentence, '$');
const char *end = strchr(sentence, '*');
if (start == NULL) return 0; // 没有找到 $
start++; // 跳过 $
const char *p = start;
// 如果存在 '*',则只计算到 '*' 前一个字符
if (end != NULL) {
while (p < end) {
checksum ^= (unsigned char)*p++;
}
} else {
// 如果没有 '*',则计算到字符串结尾
while (*p != '\0') {
checksum ^= (unsigned char)*p++;
}
}
return checksum;
}
int main()
{
char sentence[] = "$PCAS03,0,0,0,0,1,0,0,0*03\r\n"; // 示例RMC语句
unsigned char cksum = nmea_checksum(sentence);
printf("Checksum: %02X\n", cksum); // 应输出:
return 0;
}

■ ATGM336H-6N获取到的数据
■ 01. 单BDS
[2025-08-07 16:32:49.503]# RECV ASCII>
$BDRMC,083248.00,A,2240.83741,N,11349.67966,E,0.58,,070825,,,A,V34,42,42,338,18,3*41E,0.58,,070825,,,A,V34,42,42,338,18,3*41
$BDGLL,2240.83741,N,11349.67966,E,083225.00,A,A*7D
$BDZDA,083225.00,07,08,2025,00,00*73
$GPTXT,01,01,01,ANTENNA OK*35
,01,01,ANTENNA OK*35
NA OK*35
3,02,06,09,16,24,39,60,,,,,,8.7,5.3,6.8,4*3C
$BDGSV,2,1,08,02,50,241,36,06,72,244,31,09,59,229,37,13,,,19,1*4A
$BDGSV,2,2,08,16,75,251,36,24,24,203,40,39,79,302,34,60,46,243,40,1*79
$BDGSV,1,1,02,24,24,203,42,39,79,302,38,3*7C
$BDGLL,2240.84635,N,11349.68236,E,080554.00,A,A*7B
$BDZDA,080554.00,07,08,2025,00,00*71
$GPTXT,01,01,01,ANTENNA OK*35
■ 02. 双星或多星联合定位
$GNRMC,082443.000,A,2240.8299056,N,11349.6730027,E,1.08,271.40,210426,,,A,V*0D
$GNVTG,271.40,T,,M,1.08,N,2.00,K,A*28
$GNGGA,082443.000,2240.8299056,N,11349.6730027,E,1,07,2.7,73.24,M,0.00,M,,,3.5*4B
$GNGSA,A,3,05,15,29,,,,,,,,,,4.4,2.7,3.5,1*38
$GNGSA,A,3,,,,,,,,,,,,,4.4,2.7,3.5,2*31
$GNGSA,A,3,,,,,,,,,,,,,4.4,2.7,3.5,3*30
$GNGSA,A,3,02,03,21,31,,,,,,,,,4.4,2.7,3.5,4*37
$GNGSA,A,3,,,,,,,,,,,,,4.4,2.7,3.5,0*33
$GPGSV,2,1,05,05,54,312,36,15,30,209,37,19,17,148,10,20,52,186,,1*63
$GPGSV,2,2,05,29,21,320,37,1*5C
$GLGSV,1,1,00,1*78
$GAGSV,1,1,00,7*73
$BDGSV,2,1,08,02,44,241,30,03,64,189,34,06,,,28,09,,,28,1*71
$BDGSV,2,2,08,19,,,28,21,49,230,32,31,64,343,38,35,,,28,1*72
$GQGSV,1,1,00,1*65
$GNGLL,2240.8299056,N,11349.6730027,E,082443.000,A,A*4A
$GNGST,082443.000,3.7,,,,2.3,7.8,10.6*63
$GNZDA,082443.000,21,04,2026,00,00*40
$GNDHV,082443.000,0.56,0.476,0.291,-0.026,0.55,,,,,M*2E
$GPTXT,01,01,01,ANTENNA OK*35
000444.900,0.00,0.000,0.000,0.000,0.00,,,,,M*0F
$GPTXT,01,01,01,ANTENNA OK*35
■ 03. 提取经纬度代码
void AT336H_Handle(ComCtrl* com)
{
if(com->hardware.comrxBuff.writePos>270)
{
char *start = strstr((char*)com->hardware.comrxBuff.data, "RMC,"); //推荐定位信息
// printf("%s\r\n",com->hardware.comrxBuff.data);
if(start != NULL){
float data1=0,data3=0,data5=0;
char f2=0,f4=0,f6=0;
sscanf(start,"RMC,%f,%c,%f,%c,%f,%c",&data1,&f2,&data3,&f4,&data5,&f6);
if(f2=='A'){ //有效定位
//纬度
int dushu1 = data3/100;
double fen1 = (data3 - (dushu1*100))/60;
double wgs_lat = dushu1 + fen1;
//经度
int dushu2 = data5/100;
double fen2 = (data5 - (dushu2*100))/60;
double wgs_lon = dushu2 + fen2;
//double wgs_lon = 113.82811; //示例经度
//double wgs_lat = 22.680635; //示例纬度
static double gcj02[2];
wgs84_to_gcj02(wgs_lon, wgs_lat, gcj02);
gSystemInfor.sGps.lng_bd = gcj02[0];
gSystemInfor.sGps.lat_bd = gcj02[1];
// printf("----lng=%f,lat=%f\n",gSystemInfor.sGps.lng_bd,gSystemInfor.sGps.lat_bd);
}
}
com->hardware.comrxBuff.writePos=0;
}
}
■ GNSS工具GnssToolKit3
■ 坐标表示格式(数值格式)
■ 01. 十进制度(度)(Decimal Degrees, DD)
格式:经度, 纬度(注意:先经度,后纬度)
示例:113.82811, 22.680635
特点:
最常见于 API、数据库、JSON
易于计算和存储
高德、百度、Google API 都使用此格式(但坐标系不同)
■ 02. 度分秒(Degrees, Minutes, Seconds, DMS)
格式:dd° mm′ ss.sss″ N/S, ddd° mm′ ss.sss″ E/W
示例:22°40′50.286″N, 113°49′41.276″E
用法:传统测绘、航海
编程中需转换为十进制度使用:
■ 03. 度分(Degrees Minutes, DM)
格式:dd mm.mmmm N, ddd mm.mmmm E
示例:22 40.8451, 113 49.6866
常见于 NMEA 语句(如 $GPGGA)
■ 常见数据交换格式
■ 01. NMEA 0183(GPS 模块输出)
$GPGGA,062938.00,2240.8451,N,11349.6866,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*50
纬度:2240.8451,N → 22°40.8451′N
经度:11349.6866,E → 113°49.6866′E
需转换为十进制度:
const lat = 22 + 40.8451/60; // 22.6807517
const lng = 113 + 49.6866/60; // 113.8281100
■ 坐标系类型
| 模块地图 | 坐标系类型 |
|---|---|
| 来自 GPS 模块(如 ATGM336H) | WGS-84 |
| 来自高德、腾讯地图 API 返回 | GCJ-02 |
| 来自百度地图 API 返回 | BD-09 |
| 在高德地图上显示偏移大 | 很可能用了 WGS-84 未转换 |
■ ATGM336H 获取的坐标是 WGS-84坐标系,用高德解析位置会出现偏差几百米问题。
高德地图使用的是 GCJ-02 坐标系(俗称“火星坐标系”),这是中国对地理数据进行加密偏移后的坐标系统。
因此,如果你要将此坐标用于 高德开发平台(如显示在高德地图上、做逆地理编码等),必须先将其从 WGS-84 转换为 GCJ-02,否则会出现 几百米到几公里的偏差。
■ WGS-84 坐标系 转 GCJ-02 坐标系
■ 01. C
#include <math.h>
#include <stdio.h>
#define PI 3.14159265358979324
#define A 6378245.0
#define EE 0.00669342162296594323
// 判断是否在中国境内
int out_of_china(double lon, double lat) {
if (lon < 72.004 || lon > 137.8347) return 1;
if (lat < 0.8293 || lat > 55.8271) return 1;
return 0;
}
// 纬度转换
double transform_latitude(double lon, double lat) {
double ret = -100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat + 0.1 * lon * lat + 0.2 * sqrt(fabs(lon));
ret += (20.0 * sin(6.0 * lon * PI) + 20.0 * sin(2.0 * lon * PI)) * 2.0 / 3.0;
ret += (20.0 * sin(lat * PI) + 40.0 * sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * sin(lat / 12.0 * PI) + 320 * sin(lat / 30.0 * PI)) * 2.0 / 3.0;
return ret;
}
// 经度转换
double transform_longitude(double lon, double lat) {
double ret = 300.0 + lon + 2.0 * lat + 0.1 * lon * lon + 0.1 * lon * lat + 0.1 * sqrt(fabs(lon));
ret += (20.0 * sin(6.0 * lon * PI) + 20.0 * sin(2.0 * lon * PI)) * 2.0 / 3.0;
ret += (20.0 * sin(lon * PI) + 40.0 * sin(lon / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * sin(lon / 12.0 * PI) + 300.0 * sin(lon / 30.0 * PI)) * 2.0 / 3.0;
return ret;
}
// WGS-84 转 GCJ-02
void wgs84_to_gcj02(double lon, double lat, double* output) {
if (out_of_china(lon, lat)) {
output[0] = lon;
output[1] = lat;
return;
}
double d_lat = transform_latitude(lon - 105.0, lat - 35.0);
double d_lon = transform_longitude(lon - 105.0, lat - 35.0);
double rad_lat = lat / 180.0 * PI;
double magic = sin(rad_lat);
magic = 1 - EE * magic * magic;
double sqrt_magic = sqrt(magic);
d_lat = (d_lat * 180.0) / ((A * (1 - EE)) / (magic * sqrt_magic) * PI);
d_lon = (d_lon * 180.0) / (A / sqrt_magic * cos(rad_lat) * PI);
output[1] = lat + d_lat;
output[0] = lon + d_lon;
}
int main() {
double wgs_lon = 120.616662; // 示例经度
double wgs_lat = 31.233945; // 示例纬度
double gcj02[2];
wgs84_to_gcj02(wgs_lon, wgs_lat, gcj02);
printf("GCJ-02 坐标: 经度=%f, 纬度=%f\n", gcj02[0], gcj02[1]);
return 0;
}
■ 02. C++
h
#ifndef QGCTRANSFORM_H
#define QGCTRANSFORM_H
#include <QPointF>
#include <QtMath>
class QGCTransform
{
private:
// 克拉索夫斯基椭球参数
static constexpr const double a = 6378245.0; // 长半轴
static constexpr const double ee = 0.00669342162296594323; // 扁率
//判断是否在国内,不在国内则不做偏移
static bool outOfChina(double lat, double lon);
//度分格式转十进制度
static double dmToDegrees(double dm);
//纬度偏移计算
static double transformLat(double x, double y);
//经度偏移计算
static double transformLon(double x, double y);
public:
//wgs84转gcj02 返回lng,lat
static QPointF wgs84Togcj02(double wgsLat, double wgsLon);
};
#endif
cpp
#include "QGCTransform.h"
// 类外定义静态常量(C++11标准要求)
constexpr double QGCTransform::a;
constexpr double QGCTransform::ee;
bool QGCTransform::outOfChina(double lat, double lon)
{
if (lon < 72.004 || lon > 137.8347) return true;
if (lat < 0.8293 || lat > 55.8271) return true;
return false;
}
double QGCTransform::dmToDegrees(double dm)
{
// 分离度和分
int degrees = static_cast<int>(dm / 100);
double minutes = dm - degrees * 100;
// 转换公式:十进制度 = 度 + 分/60
return degrees + minutes / 60.0;
}
double QGCTransform::transformLat(double x, double y)
{
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y +
0.1 * x * y + 0.2 * sqrt(fabs(x));
ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
ret += (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
ret += (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0;
return ret;
}
double QGCTransform::transformLon(double x, double y)
{
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x +
0.1 * x * y + 0.1 * sqrt(fabs(x));
ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
ret += (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
ret += (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0;
return ret;
}
QPointF QGCTransform::wgs84Togcj02(double wgsLat, double wgsLon)
{
double wgsLat1 = dmToDegrees(wgsLat);
double wgsLon1 = dmToDegrees(wgsLon);
if (outOfChina(wgsLat1, wgsLon1))
{
return QPointF(wgsLon1, wgsLat1);
}
double dLat = transformLat(wgsLon1 - 105.0, wgsLat1 - 35.0);
double dLon = transformLon(wgsLon1 - 105.0, wgsLat1 - 35.0);
const double radLat = wgsLat1 / 180.0 * M_PI;
double magic = sin(radLat);
magic = 1 - ee * magic * magic;
const double sqrtMagic = sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * M_PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * M_PI);
return QPointF(wgsLon1 + dLon, wgsLat1 + dLat);
}
■ 在线地图
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)