1. 背景
在关于GPS定位的研究分析过程中,经常想要看在一段测试路径上,GPS的定位准确性如何,实际上,很自然的会想到把GPS数据显示在地图上,然而,并且,Google提供的Google Earth就是一个不错的工具,至于为什么不选择别的地图工具,是因为别的地图需要进行WGS84坐标系进行转换。
2. 实现代码
2.1 NMEA格式数据转化为KML的头文件
#ifndef CONVERT_H
#define CONVERT_H
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
// 模块名称: convert
// Author: HSW
// Date: 2018-01-17
// 功能: 实现NMEA GGA数据分析
//
//
// NMEA GGA 数据分析
int splitString1(string lineBuf, vector& subStrs, char dim = ',');
// ddmm.mmmm <==> dd.dddd
int fromDMToDegree(double ddmmPointMMMM, double& ddPointDDDD);
int fromDegreeToDM(double ddPointDDDD, double& ddmmPointMMMM);
// KML: 保存为KML文件
// strs: 分别包含: 描述
// 名称
// 经度
// 纬度
// 高度
int convertToKMLWithoutName(vector& pointInfo, ofstream* pOfstr, int Mode);
#endif // CONVERT_H
#include "convert.h"
#include
#include
static wstring kml_S = L"\r\n";
static wstring kmlFolder_S = L"\r\n";
static wstring kmlPlacemark_S = L"";
static wstring kmlDescription_S = L"";
static wstring kmlDescription_E = L" ";
static wstring kmlName_S = L"";
static wstring kmlName_E = L" ";
static wstring kmlLookat_S = L"";
static wstring kmlLon_S = L"";
static wstring kmlLon_E = L" ";
static wstring kmlLat_S = L"";
static wstring kmlLat_E = L" ";
static wstring kmlRange_S = L"";
static wstring kmlRange_E = L" ";
static wstring kmlTilt_S = L"";
static wstring kmlTilt_E = L" ";
static wstring kmlHeading_S = L"";
static wstring kmlHeading_E = L" ";
static wstring kmlLookat_E = L" ";
static wstring kmlPoint_S = L"";
static wstring kmlCoordinates_S = L"";
static wstring kmlCoordinates_E = L" ";
static wstring kmlPoint_E = L" ";
static wstring kmlPlacemark_E = L" \r\n";
static wstring kmlFolder_E = L" \r\n";
static wstring kml_E = L" \r\n";
static wstring kml_default_range = L"20000";
static wstring kml_default_tilt = L"0";
static wstring kml_default_heading = L"3";
static string kml_default_altitude = "0";
static wstring kml_default_pointSetName = L"Positions";
// 实现差分前后的数据处理
//
static char exampleGGA[4][128] = {"$GPGGA,062926.000,4538.7429,N,12639.4155,E,2,08,1.0,196.6,M,0.0,M,23,1544*6C",
"$GPGGA,062926.000,4538.7429,N,12639.4155,W,2,08,1.0,196.6,M,0.0,M,23,1544*6C",
"$GPGGA,062926.000,4538.7429,S,12639.4155,E,2,08,1.0,196.6,M,0.0,M,23,1544*6C",
"$GPGGA,062926.000,4538.7429,N,12639.4155,W,2,08,1.0,196.6,M,0.0,M,23,1544*6C"};
// 将std::string 转为 利用UTF-8编码的std::string
// step1: 将std::string 转为 std::wstring
// 方法1:
BOOL StringToWString(const std::string &str,std::wstring &wstr)
{
int nLen = (int)str.length();
wstr.resize(nLen,L' ');
int nResult = MultiByteToWideChar(CP_ACP,0,(LPCSTR)str.c_str(),nLen,(LPWSTR)wstr.c_str(),nLen);
if (nResult == 0)
{
return FALSE;
}
return TRUE;
}
//wstring高字节不为0,返回FALSE
BOOL WStringToString(const std::wstring &wstr,std::string &str)
{
int nLen = (int)wstr.length();
str.resize(nLen,' ');
int nResult = WideCharToMultiByte(CP_ACP,0,(LPCWSTR)wstr.c_str(),nLen,(LPSTR)str.c_str(),nLen,NULL,NULL);
if (nResult == 0)
{
return FALSE;
}
return TRUE;
}
std::string to_utf8(const wchar_t* buffer, int len)
{
int nChars = ::WideCharToMultiByte(
CP_UTF8,
0,
buffer,
len,
NULL,
0,
NULL,
NULL);
if (nChars == 0) return "";
string newbuffer;
newbuffer.resize(nChars) ;
::WideCharToMultiByte(
CP_UTF8,
0,
buffer,
len,
const_cast< char* >(newbuffer.c_str()),
nChars,
NULL,
NULL);
return newbuffer;
}
// std::string 转为 std::string UTF-8
std::string to_utf8(const std::wstring& str)
{
return to_utf8(str.c_str(), (int)str.size());
}
// NMEA GGA 数据分析
int splitString1(string lineBuf, vector& subStrs, char dim)
{
size_t startPos = lineBuf.find('$');
size_t endPos = lineBuf.find('*');
int iter;
int count = 0;
char subStr[64] = {0};
int findGGA = 0;
if(startPos != string::npos && endPos != string::npos)
{
for(iter = startPos + 1; iter < endPos; ++iter)
{
char ch = lineBuf.at(iter);
if(ch == dim)
{
string tmp = string(subStr);
if(tmp.find("GGA") != string::npos)
{
findGGA = 1;
}
subStrs.push_back(string(subStr));
memset(subStr,0, sizeof(subStr));
count = 0;
}
else
{
subStr[count] = lineBuf.at(iter);
count++;
}
}
subStrs.push_back(string(subStr));
}
if(findGGA)
{
return 0;
}
else
{
return -1;
}
}
// DD.DDDD ==> ddmm.mmmm
int fromDegreeToDM(double ddPointDDDD, double& ddmmPointMMMM)
{
int tmpInt = (int)floor(ddPointDDDD);
double tmpFloat = ddPointDDDD - tmpInt;
ddmmPointMMMM = tmpInt * 100 + tmpFloat * 60;
return 0;
}
// ddmm.mmmm ==> DD.DDDD
int fromDMToDegree(double ddmmPointMMMM, double& ddPointDDDD)
{
int tmpInt = floor(ddmmPointMMMM / 100);
double tmpFloat = ddmmPointMMMM - tmpInt * 100;
ddPointDDDD = tmpInt + tmpFloat / 60;
return 0;
}
// nmea 计算检查和
unsigned char checkSum(const char* buf)
{
int isStart = 0;
int iter = 0;
unsigned char checksum = 0;
while(1)
{
if((unsigned char)buf[iter] == '$')
{
isStart = 1;
++iter;
continue;
}
if(isStart)
{
if((unsigned char)buf[iter] == '*')
{
break;
}
checksum ^= buf[iter];
}
++iter;
}
// cout << "checksum = " << checksum << endl;
return checksum;
}
// KML: 保存为KML文件, 不包含点的名称
// strs: 分别包含: 描述
// 经度
// 纬度
// 注意:坐标点的高度默认设置为0
int convertToKMLWithoutName(vector& pointInfo, ofstream* pOfstr, int Mode)
{
wstring utf8wStr = L""; // 宽字符
string utf8Str = ""; // UTF-8字符串
if(Mode == 0)
{
utf8Str = to_utf8(kml_S);
// pOfstr->write(kml_S.c_str(), kml_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8Str = to_utf8(kmlFolder_S);
// pOfstr->write(kmlFolder_S.c_str(), kmlFolder_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// 名称: kml文件的名称
utf8Str = to_utf8(kmlName_S);
//pOfstr->write(kmlName_S.c_str(), kmlName_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
StringToWString(pointInfo[0], utf8wStr);
utf8Str = to_utf8(utf8wStr);
//pOfstr->write(pointInfo[0].c_str(), pointInfo[0].length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlName_E);
// pOfstr->write(kmlName_E.c_str(), kmlName_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// 点集合名称: kml
// 点集合名称: kml
string outputPath = pointInfo[0];
size_t pos = outputPath.find_last_of('/');
if(pos != string::npos)
{
utf8Str = to_utf8(kmlName_S);
//pOfstr->write(kmlName_S.c_str(), kmlName_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// utf8Str = to_utf8(kml_default_pointSetName);
//pOfstr->write(kml_default_pointSetName.c_str(), kml_default_pointSetName.length());
CTMStrConvert converter;
wstring wPointsetName = converter.StringToWString(outputPath.substr(pos + 1, outputPath.length() - pos -1));
utf8Str = converter.WStringToUtf8(wPointsetName);
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlName_E);
// pOfstr->write(kmlName_E.c_str(), kmlName_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
}
else
{
utf8Str = to_utf8(kmlName_S);
//pOfstr->write(kmlName_S.c_str(), kmlName_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8Str = to_utf8(kml_default_pointSetName);
//pOfstr->write(kml_default_pointSetName.c_str(), kml_default_pointSetName.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlName_E);
// pOfstr->write(kmlName_E.c_str(), kmlName_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
}
wstring lineBuf = L"\r\n";
utf8Str = to_utf8(lineBuf);
// pOfstr->write(lineBuf.c_str(), lineBuf.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
}
else if(Mode == 1)
{
// Placemark
utf8Str = to_utf8(kmlPlacemark_S);
// pOfstr->write(kmlPlacemark_S.c_str(), kmlPlacemark_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// -描述
utf8Str = to_utf8(kmlDescription_S);
// pOfstr->write(kmlDescription_S.c_str(), kmlDescription_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
StringToWString(pointInfo[0], utf8wStr);
utf8Str = to_utf8(utf8wStr);
// pOfstr->write(pointInfo[0].c_str(), pointInfo[0].length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlDescription_E);
// pOfstr->write(kmlDescription_E.c_str(), kmlDescription_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
#if 0
// -名称
utf8Str = to_utf8(kmlName_S);
//pOfstr->write(kmlName_S.c_str(), kmlName_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
StringToWString(pointInfo[1], utf8wStr);
utf8Str = to_utf8(utf8wStr);
// pOfstr->write(pointInfo[1].c_str(), pointInfo[1].length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlName_E);
// pOfstr->write(kmlName_E.c_str(), kmlName_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
#endif
// -LookAt
utf8Str = to_utf8(kmlLookat_S);
// pOfstr->write(kmlLookat_S.c_str(), kmlLookat_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// --lon 经度
utf8Str = to_utf8(kmlLon_S);
// pOfstr->write(kmlLon_S.c_str(), kmlLon_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
StringToWString(pointInfo[1], utf8wStr);
utf8Str = to_utf8(utf8wStr);
// pOfstr->write(pointInfo[2].c_str(), pointInfo[2].length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlLon_E);
// pOfstr->write(kmlLon_E.c_str(), kmlLon_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// --lat 纬度
utf8Str = to_utf8(kmlLat_S);
// pOfstr->write(kmlLat_S.c_str(), kmlLat_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
StringToWString(pointInfo[2], utf8wStr);
utf8Str = to_utf8(utf8wStr);
// pOfstr->write(pointInfo[3].c_str(), pointInfo[3].length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlLat_E);
// pOfstr->write(kmlLat_E.c_str(), kmlLat_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// --range
utf8Str = to_utf8(kmlRange_S);
// pOfstr->write(kmlRange_S.c_str(), kmlRange_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8Str = to_utf8(kml_default_range);
// pOfstr->write(kml_default_range.c_str(), kml_default_range.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlRange_E);
// pOfstr->write(kmlRange_E.c_str(), kmlRange_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// --tilt
utf8Str = to_utf8(kmlTilt_S);
// pOfstr->write(kmlTilt_S.c_str(), kmlTilt_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8Str = to_utf8(kml_default_tilt);
// pOfstr->write(kml_default_tilt.c_str(), kml_default_tilt.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlTilt_E);
// pOfstr->write(kmlTilt_E.c_str(), kmlTilt_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// --heading
utf8Str = to_utf8(kmlHeading_S);
// pOfstr->write(kmlHeading_S.c_str(), kmlHeading_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8Str = to_utf8(kml_default_heading);
// pOfstr->write(kml_default_heading.c_str(), kml_default_heading.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
utf8Str = to_utf8(kmlHeading_E);
// pOfstr->write(kmlHeading_E.c_str(), kmlHeading_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// -LookAt
utf8Str = to_utf8(kmlLookat_E);
// pOfstr->write(kmlLookat_E.c_str(), kmlLookat_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// -Point
utf8Str = to_utf8(kmlPoint_S);
// pOfstr->write(kmlPoint_S.c_str(), kmlPoint_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// --coordinate
utf8Str = to_utf8(kmlCoordinates_S);
// pOfstr->write(kmlCoordinates_S.c_str(), kmlCoordinates_S.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
string coordinate = pointInfo[1] + "," + pointInfo[2] + "," + kml_default_altitude;
StringToWString(coordinate, utf8wStr);
utf8Str = to_utf8(utf8wStr);
// pOfstr->write(coordinate.c_str(), coordinate.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8wStr.clear();
// --coordinate
utf8Str = to_utf8(kmlCoordinates_E);
// pOfstr->write(kmlCoordinates_E.c_str(), kmlCoordinates_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// -Point
utf8Str = to_utf8(kmlPoint_E);
// pOfstr->write(kmlPoint_E.c_str(), kmlPoint_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
// Placemark
utf8Str = to_utf8(kmlPlacemark_E);
// pOfstr->write(kmlPlacemark_E.c_str(), kmlPlacemark_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
}
else if(Mode == 2)
{
utf8Str = to_utf8(kmlFolder_E);
// pOfstr->write(kmlFolder_E.c_str(), kmlFolder_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
utf8Str = to_utf8(kml_E);
// pOfstr->write(kml_E.c_str(), kml_E.length());
pOfstr->write(utf8Str.c_str(), utf8Str.length());
utf8Str.clear();
}
pOfstr->flush();
return 0;
}
2.2 ASCII字符集和UTF-8字符集转换类
#ifndef CTMSTRCONVERT_H
#define CTMSTRCONVERT_H
#include
#include
#include
#include
using namespace std;
// 模块名称:windows中字符串转换类
// Author: HSW
// Date: 2018-01-30
// 功能: 实现多字节字符串与宽字节字符串之间的转换
// 多字节集合: ASCII / UTF8 等, 一般情况下,ASCII为常用的字符串;UTF8主要在网页
// 宽字节集合: 表示汉字等需要使用宽字节
class CTMStrConvert
{
public:
CTMStrConvert();
~CTMStrConvert();
public:
wstring StringToWString(const char* abuffer, const int nLen);
wstring StringToWString(const string &astr);
wstring Utf8ToWString(const char* ubuffer, int nLen);
wstring Utf8ToWString(const string ustr);
string WStringToString(const wchar_t* wbuffer, const int nLen);
string WStringToString(const wstring &wstr);
string WStringToUtf8(const wchar_t* wbuffer, int nLen);
string WStringToUtf8(const wstring& wstr);
string StringToUtf8(const string &astr);
string StringToUtf8(const char* abuffer, const int nLen);
string Utf8ToString(const string ustr);
string Utf8ToString(const char* ubuffer, const int nLen);
};
#endif // CTMSTRCONVERT_H
#include "ctmstrconvert.h"
CTMStrConvert::CTMStrConvert()
{
}
CTMStrConvert::~CTMStrConvert()
{
}
// 功能: 多字节(ASCII)字符串转宽字节字符串
// aBuffer: ASCII的多字节字符数组
// nLen: ASCII的多字节数组长度
// 返回: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
wstring CTMStrConvert::StringToWString(const char* abuffer, const int nLen)
{
// 需要的缓冲区大小
int nResult = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)abuffer, nLen, NULL, 0);
if (nResult == 0)
{
cout << "Get Wide Char Buffer Size Failed " << endl;
return L"";
}
wstring wstr;
wstr.resize(nResult, L' ');
nResult = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)abuffer, nLen, (LPWSTR)wstr.c_str(), nResult);
if(nResult == 0)
{
cout << "From MultiByte To Wide Char Translate Failed " << endl;
return L"";
}
else
{
return wstr;
}
}
// 功能: 多字节(ASCII)字符串转宽字节字符串
// astr: ASCII的多字节字符串
// 返回: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
wstring CTMStrConvert::StringToWString(const string &astr)
{
return StringToWString(astr.c_str(), astr.length());
}
// 功能: 宽字节字符数组转为多字节(ASCII)字符串
// wbuffer: ASCII的多字节字符串
// len: 宽字节字符串
// 返回: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
string CTMStrConvert::WStringToString(const wchar_t* wbuffer, const int nLen)
{
// 获取需要的缓冲区的大小
int nResult = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)wbuffer, nLen, NULL, 0, NULL, NULL);
if (nResult == 0)
{
cout << "Get Multi Byte Buffer Size Failed " << endl;
return "";
}
string astr;
astr.resize(nResult, ' ');
nResult = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)wbuffer, nLen, (LPSTR)astr.c_str(), nResult, NULL, NULL);
if (nResult == 0)
{
cout << "From Wide Char To Multi Byte Translate Failed " << endl;
return "";
}
else
{
return astr;
}
}
// 功能: 宽字节字符串转为多字节(ASCII)字符串
// wstr: 宽字节字符串
// 返回: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
string CTMStrConvert::WStringToString(const wstring &wstr)
{
return WStringToString(wstr.c_str(), wstr.length());
}
// 功能: 宽字节字符数组转为UTF-8多字节字符串
// wbuffer: 宽字节字符数组
// nLen: 宽字节字符数组的长度
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
string CTMStrConvert::WStringToUtf8(const wchar_t* wbuffer, int nLen)
{
// 获取所需的缓冲区大小
int nResult = WideCharToMultiByte(CP_UTF8, 0, wbuffer, nLen, NULL, 0, NULL, NULL);
if (nResult == 0)
{
cout << "Get Multi Byte Buffer Size Failed " << endl;
return "";
}
string ustr;
ustr.resize(nResult, ' ');
nResult = WideCharToMultiByte(CP_UTF8, 0, wbuffer, nLen, const_cast< char* >(ustr.c_str()), nResult, NULL, NULL);
if(nResult == 0)
{
cout << "Wide Char To Multi Byte Translate Failed " << endl;
return "";
}
else
{
return ustr;
}
}
// 功能: 宽字节字符串 转为 UTF-8
// wstr: 宽字节字符串
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
string CTMStrConvert::WStringToUtf8(const wstring& wstr)
{
return WStringToUtf8(wstr.c_str(), (int)wstr.size());
}
// 功能: UTF-8多字节数组 转为 宽字节字符串
// ubuffer: UTF-8多字节数组
// len: UTF-8多字节数组长度
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
//
wstring CTMStrConvert::Utf8ToWString(const char* ubuffer, int nLen)
{
// 需要的缓冲区大小
int nResult = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ubuffer, nLen, NULL, 0);
if (nResult == 0)
{
cout << "Get Wide Char Buffer Size Failed " << endl;
return L"";
}
wstring wstr;
wstr.resize(nResult, L' ');
nResult = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ubuffer, nLen, (LPWSTR)wstr.c_str(), nResult);
if(nResult == 0)
{
cout << "From MultiByte To Wide Char Translate Failed " << endl;
return L"";
}
else
{
return wstr;
}
}
// 功能: UTF-8多字节字符串 转为 宽字节字符串
// ustr: UTF-8多字节字符串
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-01-30
// 修改记录:
wstring CTMStrConvert::Utf8ToWString(const string ustr)
{
return Utf8ToWString(ustr.c_str(), ustr.length());
}
// 功能: 多字节(ASCII)字符串 转为 UTF-8多字节字符串
// astr: 多字节(ASCII)字符串
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-03-29
// 修改记录:
string CTMStrConvert::StringToUtf8(const string &astr)
{
wstring wstr = StringToWString(astr);
return WStringToUtf8(wstr);
}
// 功能: 多字节(ASCII)字符串 转为 UTF-8多字节字符串
// abuffer: 多字节(ASCII)字符串
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-03-29
// 修改记录:
string CTMStrConvert::StringToUtf8(const char* abuffer, const int nLen)
{
wstring wstr = StringToWString(abuffer, nLen);
return WStringToUtf8(wstr);
}
// 功能: UTF-8多字节字符串 转为 多字节(ASCII)字符串
// ustr: UTF-8多字节字符串
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-03-29
// 修改记录:
string CTMStrConvert::Utf8ToString(const string ustr)
{
wstring wstr = Utf8ToWString(ustr);
return WStringToString(wstr);
}
// 功能: UTF-8多字节字符串 转为 多字节(ASCII)字符串
// ubuffer: UTF-8多字节字符串
// 返回值: 成功返回包含内容的字符串,失败返回空串
// 日期: 2018-03-29
// 修改记录:
string CTMStrConvert::Utf8ToString(const char* ubuffer, const int nLen)
{
wstring wstr = Utf8ToWString(ubuffer, nLen);
return WStringToString(wstr);
}
2.3 QT界面类
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
using namespace std;
namespace Ui {
class MainWindow;
}
typedef struct st_Support_Format
{
unsigned int supportTXT;
unsigned int supportCSV;
unsigned int supportRDF;
}st_Support_Format;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void initialWindows();
int getFilePaths();
private slots:
void auto_slot();
void split_slot();
void batch_slot();
void support_txt_slot();
void support_csv_slot();
void openfile_slot();
void nmea_slot();
private:
Ui::MainWindow* ui;
unsigned int m_isAuto; // 是否通过Google自动打开
unsigned int m_isSplit; // 是否对每个KML文件分开显示
unsigned int m_isBatch; // 是否批处理
string m_googleEarthPath; // google Earth 的路径
string m_firstPath; // 选择的文件路径
string m_guiFirstPath; // 用于在GUI显示选择的文件路径
vector m_filePaths; // 文件路径
st_Support_Format m_supportFormat; // 支持的文件格式
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "convert.h"
#include "ctmstrconvert.h"
#include
#include
#include
#include
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化windows
initialWindows();
// Connect <===> Slot
connect(ui->autoCheckBox, SIGNAL(clicked(bool)), this, SLOT(auto_slot()));
connect(ui->splitCheckBox, SIGNAL(clicked(bool)), this, SLOT(split_slot()));
connect(ui->batchCheckBox, SIGNAL(clicked(bool)), this, SLOT(batch_slot()));
connect(ui->txtCheckBox, SIGNAL(clicked(bool)), this, SLOT(support_txt_slot()));
connect(ui->csvCheckBox, SIGNAL(clicked(bool)), this, SLOT(support_csv_slot()));
connect(ui->openFilePushButton, SIGNAL(clicked(bool)), this, SLOT(openfile_slot()));
connect(ui->convertNMEAPushButton, SIGNAL(clicked(bool)), this, SLOT(nmea_slot()));
// 设置support Push Button 的边框
ui->supportPushButton->setEnabled(false);
ui->supportPushButton->setStyleSheet("border: none");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initialWindows()
{
if(ui->autoCheckBox->isChecked())
{
m_isAuto = 1;
ui->splitCheckBox->setEnabled(true);
}
else
{
m_isAuto = 0;
ui->splitCheckBox->setEnabled(false);
}
if(ui->splitCheckBox->isChecked())
{
m_isSplit = 1;
}
else
{
m_isSplit = 0;
}
if(ui->batchCheckBox->isChecked())
{
m_isBatch = 1;
ui->txtCheckBox->setEnabled(true);
ui->csvCheckBox->setEnabled(true);
}
else
{
m_isBatch = 0;
ui->txtCheckBox->setEnabled(false);
ui->csvCheckBox->setEnabled(false);
}
m_firstPath = ""; // 初始化为空
m_filePaths.clear();
QPixmap imagePix;
imagePix.load("gpsImage.jpg"); // 加载
ui->tmLabel->setScaledContents(true); // 设置自适应
ui->tmLabel->clear(); // 清空
ui->tmLabel->setPixmap(imagePix); // 加载到Label标签
ui->tmLabel->show(); // 显示
}
void MainWindow::auto_slot()
{
if(ui->autoCheckBox->isChecked())
{
m_isAuto = 1;
ui->splitCheckBox->setEnabled(true);
// Check Google Earth
QSettings *configIniRead = new QSettings("TM_Google_Earth.ini", QSettings::IniFormat);
QString googleEarthPath = configIniRead->value("/Path/googleEarthPath").toString();
// qDebug() << googleEarthPath;
if(googleEarthPath.isEmpty())
{
// 释放文件
configIniRead->deleteLater();
// 弹出选择google Earth 的路径
QMessageBox Msg(QMessageBox::Question,
QString(tr("配置GoogleEarth")),
QString(tr("选择GoogleEarth路径(例如:C:\\Program Files (x86)\\Google\\Google Earth\\client\\googleearth.exe)")));
QAbstractButton *pYesBtn = (QAbstractButton *)Msg.addButton(QString(tr("是")), QMessageBox::YesRole);
QAbstractButton *pNoBtn = (QAbstractButton *)Msg.addButton(QString(tr("否")), QMessageBox::NoRole);
Msg.exec();
if (Msg.clickedButton() != pYesBtn)
{
m_isAuto = 0;
ui->autoCheckBox->setChecked(false);
ui->splitCheckBox->setEnabled(false);
return ;
}
// 文件选择对话框:选择Google Earth 路径
QString qFilePath = QFileDialog::getOpenFileName(this, QString(tr("选择GoogleEarth路径")), "", "File(*.exe)", NULL);
if(!qFilePath.isEmpty())
{
m_googleEarthPath = qFilePath.toStdString();
QSettings *configIniWrite = new QSettings("TM_Google_Earth.ini", QSettings::IniFormat);
//向ini文件中写入内容,setValue函数的两个参数是键值对
configIniWrite->setValue("/Path/googleEarthPath", qFilePath);
configIniWrite->deleteLater();
}
else
{
QMessageBox Msg(QMessageBox::Question,
QString(tr("配置GoogleEarth")),
QString(tr("设置Google Earth 路径失败!")));
Msg.exec();
m_isAuto = 0;
ui->splitCheckBox->setEnabled(false);
}
}
else
{
m_googleEarthPath = googleEarthPath.toStdString();
configIniRead->deleteLater();
}
}
else
{
m_isAuto = 0;
ui->splitCheckBox->setEnabled(false);
}// if ... else ... isChecked()
}
void MainWindow::split_slot()
{
if(ui->splitCheckBox->isChecked())
{
m_isSplit = 1;
}
else
{
m_isSplit = 0;
}
}
void MainWindow::batch_slot()
{
if(ui->batchCheckBox->isChecked())
{
m_isBatch = 1;
ui->txtCheckBox->setEnabled(true);
ui->csvCheckBox->setEnabled(true);
}
else
{
m_isBatch = 0;
ui->txtCheckBox->setChecked(false);
ui->csvCheckBox->setChecked(false);
ui->txtCheckBox->setEnabled(false);
ui->csvCheckBox->setEnabled(false);
}
if(!ui->txtCheckBox->isChecked()
&& !ui->csvCheckBox->isChecked())
{
ui->convertNMEAPushButton->setEnabled(true);
}
}
void MainWindow::support_txt_slot()
{
if(ui->txtCheckBox->isChecked())
{
m_supportFormat.supportTXT = 1;
ui->convertNMEAPushButton->setEnabled(true);
}
else
{
m_supportFormat.supportTXT = 0;
if(!ui->txtCheckBox->isChecked()
&& !ui->csvCheckBox->isChecked())
{
ui->convertNMEAPushButton->setEnabled(true);
}
else if(!ui->csvCheckBox->isChecked())
{
ui->convertNMEAPushButton->setEnabled(false);
}
}
}
void MainWindow::support_csv_slot()
{
if(ui->csvCheckBox->isChecked())
{
m_supportFormat.supportCSV = 1;
ui->convertNMEAPushButton->setEnabled(true);
}
else
{
m_supportFormat.supportCSV = 0;
if(!ui->txtCheckBox->isChecked()
&& !ui->csvCheckBox->isChecked())
{
ui->convertNMEAPushButton->setEnabled(true);
}
else if(!ui->txtCheckBox->isChecked())
{
ui->convertNMEAPushButton->setEnabled(false);
}
}
}
void MainWindow::openfile_slot()
{
if(m_isBatch)
{// 批量处理
QString qFileDir = QFileDialog::getExistingDirectory(this, QString(tr("选择文件夹")), "");
if(!qFileDir.isEmpty())
{
QTextCodec *codec =QTextCodec::codecForName("UTF-8");
QString str = codec->toUnicode(qFileDir.toStdString().c_str());
wstring fileName = str.toStdWString();
CTMStrConvert converter;
m_firstPath = converter.WStringToString(fileName);
m_guiFirstPath = qFileDir.toStdString();
}
else
{
m_firstPath = "";
m_guiFirstPath = "";
}
}
else
{// 处理单个文件
QString qFilePath = QFileDialog::getOpenFileName(this, QString(tr("选择文件")), "", "File(*.txt *.csv)", NULL);
if(!qFilePath.isEmpty())
{
QTextCodec *codec =QTextCodec::codecForName("UTF-8");
QString str = codec->toUnicode(qFilePath.toStdString().c_str());
wstring fileName = str.toStdWString();
CTMStrConvert converter;
m_firstPath = converter.WStringToString(fileName);
m_guiFirstPath = qFilePath.toStdString();
}
else
{
m_firstPath = "";
m_guiFirstPath = "";
}
}
ui->openTextBrowser->setText(QString::fromStdString(m_guiFirstPath));
}
void MainWindow::nmea_slot()
{
int ret;
ret = getFilePaths();
if(ret == 0)
{
vector kmlPaths; // 存储输出的kml文件路径
vector::iterator iter;
for(iter = m_filePaths.begin(); iter != m_filePaths.end(); ++iter)
{
ifstream ifstr(*iter, ios_base::binary | ios_base::in);
string outputFilePath = (*iter) + ".kml";
ofstream* pOfstr = new ofstream(outputFilePath, ios_base::out | ios_base::binary | ios_base::trunc);
if(pOfstr == NULL)
{
QString message = QString(tr("打开(创建)输出文件(")) + QString::fromStdString(outputFilePath) + QString(tr(")失败"));
QMessageBox msgBox(QMessageBox::Warning,"Information",message,QMessageBox::Yes,NULL);
msgBox.exec();
continue;
}
else if(!pOfstr->is_open())
{
QString message = QString(tr("打开(创建)输出文件(")) + QString::fromStdString(outputFilePath) + QString(tr(")失败"));
QMessageBox msgBox(QMessageBox::Warning,"Information",message,QMessageBox::Yes,NULL);
msgBox.exec();
continue;
}
if(ifstr.is_open())
{
int isFirst = 1;
vector kmlPointInfo;
int emptyCnt = 0;
char bufPos[64] = {0};
while(1)
{
char buf[256] = {0};
ifstr.getline(buf, sizeof(buf));
int buflen = strlen((const char*)buf);
if(buflen > 32)
{
vector substrs;
ret = splitString1(string(buf), substrs, ',');
if(ret < 0)
{
continue;
}
if(isFirst)
{
kmlPointInfo.clear();
kmlPointInfo.push_back(outputFilePath);
ret = convertToKMLWithoutName(kmlPointInfo, pOfstr, 0); //
if(ret < 0)
{
continue;
}
isFirst = 0;
}
if(!isFirst)
{
kmlPointInfo.clear();
kmlPointInfo.push_back(substrs[1]); // utcTime
double lonDDPointDDDD;
double lonDDMMPointMMMM;
stringstream sLon1(substrs[4]);
sLon1 >> lonDDMMPointMMMM;
fromDMToDegree(lonDDMMPointMMMM, lonDDPointDDDD);
memset(bufPos, 0, sizeof(bufPos));
sprintf(bufPos, "%lf", lonDDPointDDDD);
kmlPointInfo.push_back(string(bufPos)); // Lon: 经度
double latDDPointDDDD;
double latDDMMPointMMMM;
stringstream sLat1(substrs[2]);
sLat1 >> latDDMMPointMMMM;
fromDMToDegree(latDDMMPointMMMM, latDDPointDDDD);
memset(bufPos, 0, sizeof(bufPos));
sprintf(bufPos, "%lf", latDDPointDDDD);
kmlPointInfo.push_back(string(bufPos)); // Lat
ret = convertToKMLWithoutName(kmlPointInfo, pOfstr, 1);
if(ret < 0)
{
continue;
}
}
emptyCnt = 0;
continue;
}
else if(buflen > 0)
{
emptyCnt = 0;
continue;
}
else
{
emptyCnt++;
}
if(emptyCnt > 20)
{
break;
}
}
ret = convertToKMLWithoutName(kmlPointInfo, pOfstr, 2); // kml 文件结束
ifstr.close();
pOfstr->close();
delete pOfstr;
pOfstr = NULL;
kmlPaths.push_back(outputFilePath);
QMessageBox msgBox(QMessageBox::Warning,"Information",tr("处理完成"),QMessageBox::Yes,NULL);
msgBox.exec();
}
else
{
QString message = QString(tr("打开文件(")) + QString::fromStdString(*iter) + QString(tr(")失败"));
QMessageBox msgBox(QMessageBox::Warning,"Information",message,QMessageBox::Yes,NULL);
msgBox.exec();
}
}//for
// 利用Google Earth 自动打开
if(m_isAuto)
{
CTMStrConvert converter;
wstring googleEarthPath = converter.StringToWString(m_googleEarthPath);
vector::iterator iterKmlPath;
if(m_isSplit)
{// 每个KML文件单独显示
for(iterKmlPath = kmlPaths.begin(); iterKmlPath != kmlPaths.end(); ++iterKmlPath)
{
string kmlPath = *iterKmlPath;
wstring wkmlPath = converter.StringToWString(kmlPath);
HINSTANCE ret = ShellExecute(NULL, L"open", googleEarthPath.c_str(), wkmlPath.c_str(), NULL, SW_SHOWNORMAL);
if((int)ret < 32)
{
int errorNo = (int)ret;
QString message = QString(tr("启动Google Earth 显示 KML 文件:("))
+ QString::fromStdString(kmlPath)
+ QString(tr(") 失败, Error Code: "))
+ QString::number(errorNo);
QMessageBox msgBox(QMessageBox::Warning,"Information",message,QMessageBox::Yes,NULL);
msgBox.exec();
}
}
}
else
{// 全部KML文件同时显示
wstring wkmlPath;
for(iterKmlPath = kmlPaths.begin(); iterKmlPath != kmlPaths.end(); ++iterKmlPath)
{
string kmlPath = *iterKmlPath;
wkmlPath += converter.StringToWString(kmlPath) + wstring(L" ");
}
HINSTANCE ret = ShellExecute(NULL, L"open", googleEarthPath.c_str(), wkmlPath.c_str(), NULL, SW_SHOWNORMAL);
if((int)ret < 32)
{
int errorNo = (int)ret;
QString message = QString(tr("启动Google Earth 显示 KML 文件失败, Error Code: ")) + QString::number(errorNo);
QMessageBox msgBox(QMessageBox::Warning,"Information",message,QMessageBox::Yes,NULL);
msgBox.exec();
}
}
}// if m_isAuto
}// if ret
}
int MainWindow::getFilePaths()
{
if(m_firstPath.empty())
{
QMessageBox msgBox(QMessageBox::Warning,"Information",tr("未选择文件(夹),请选择"),QMessageBox::Yes,NULL);
msgBox.exec();
return -1;
}
// 清空路径
if(!m_filePaths.empty())
{
m_filePaths.clear();
}
if(m_isBatch)
{// 遍历文件夹
QDir dir(QString::fromStdString(m_firstPath));
int supportCnt = m_supportFormat.supportTXT + m_supportFormat.supportCSV + m_supportFormat.supportRDF;
if(supportCnt == 0)
{
QMessageBox msgBox(QMessageBox::Warning,"Information",tr("文件夹中无.txt/.csv/.rdf文件格式文件,请确定"),QMessageBox::Yes,NULL);
msgBox.exec();
return -1;
}
foreach(QFileInfo mfi ,dir.entryInfoList())
{
if(mfi.isFile())
{
QString filePath = mfi.filePath();
QString fileName = mfi.fileName();
string sfileName = fileName.toLower().toStdString();
if(m_supportFormat.supportTXT)
{
if(sfileName.find(".txt") != string::npos)
{
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QString str = codec->toUnicode(filePath.toStdString().c_str());
wstring wFilePath = str.toStdWString();
CTMStrConvert converter;
m_filePaths.push_back(converter.WStringToString(wFilePath));
// m_filePaths.push_back(filePath.toStdString());
}
}
if(m_supportFormat.supportCSV)
{
if(sfileName.find(".csv") != string::npos)
{
QTextCodec *codec =QTextCodec::codecForName("UTF-8");
QString str = codec->toUnicode(filePath.toStdString().c_str());
wstring wFilePath = str.toStdWString();
CTMStrConvert converter;
m_filePaths.push_back(converter.WStringToString(wFilePath));
// m_filePaths.push_back(filePath.toStdString());
}
}
if(m_supportFormat.supportRDF)
{
if(sfileName.find(".rdf") != string::npos)
{
QTextCodec *codec =QTextCodec::codecForName("UTF-8");
QString str = codec->toUnicode(filePath.toStdString().c_str());
wstring wFilePath = str.toStdWString();
CTMStrConvert converter;
m_filePaths.push_back(converter.WStringToString(wFilePath));
// m_filePaths.push_back(filePath.toStdString());
}
}
}
else
{
continue;
}
}
}
else
{
m_filePaths.push_back(m_firstPath);
}
if(m_filePaths.size() == 0)
{
QMessageBox msgBox(QMessageBox::Warning,"Information",tr("无有效文件,请确定"),QMessageBox::Yes,NULL);
msgBox.exec();
return -1;
}
return 0;
}
2.4 UI文件请到如下路径下载,同时也包含可执行文件(.exe):
https://download.csdn.net/download/hit1524468/10316766
3. 工具效果(选择用googleEarth打开转换的KML文件)