安卓端益动GPS数据导出轨迹信息
本文写于2024年2月5日
益动GPS应该是国内最早一批做定位轨迹以及记录运动的App,非常可惜,当时我记得是乐视注资了还是投资了,结果后面也是慢慢停止服务了,最开始是同步不了记录,微博还有人运营,到后面微博也人运营, 官网也打不开,app登录不上去了。
追溯到最早用这个app的时候还是2014年。

让我耿耿于怀的是,其中有一条我骑行了一整天共130多公里记录的,从7点不到出门,到快7点才到家,这条记录一直都在手机里存着, 伴随着我换了两次手机,这个app还在我手机里躺着。
当时奈何技术不够,一直想用什么方法导出来,年轻的菜鸟终于有折腾出来方法了。
思路:
- 用安卓的adb工具,备份出app的所有数据。(发现MIUI直接在手机的备份中,选定应用,备份一下导出电脑解压就可以了。)
- 分析备份出来的内容,发现有db结尾后缀的文件,熟悉开发的人都知道,这是Sqlite数据库的文件。
- 解析数据,导出gpx文件格式的数据
- 发现还不能用,还得进行转换,才能用到国内的地图源上 WGS->GCJ
- 轨迹叠加地图导出视频 GPX animator / Telemetry Overlay / 佳明Virb
备份【益动GPS】并解压出文件
手机用的都是几年前的红米手机,导出数据的过程比较顺利,开始以为一定要用adb工具的backup命令才能备份出来,结果发现MIUI自带的备份,会直接把应用数据打包, 也没有加密,不知道新版的MIUI还行不行。
测试 基于MIUI 12.0.11 Redmi Note 9 Pro Android 10 / MIUI12.0.2 XiaoMi 6X Andoroid 9 / Miui XiaoMi 4C (4C不记得具体版本了..)
【设置】——【我的设备】——【备份与恢复】——【手机备份恢复】——【输入锁屏密码】——【选择第三方应用】——【开始备份】


然后从手机上拷贝对应路径 /存储根目录/MIUI/backup/AllBackup/[备份日期_时间]/益动GPS(com.edooon.gps).bak
到电脑上,直接用解压缩软件,解压出来。

分析备份出的应用数据
db文件夹中,包含一些.db后缀的文件,从大到小排序,不出以为,数据应该在最大的.db文件里。

随便用个Sqlite查看器打开,果不其然。并且找到第一条记录时2016年1月6日的。


数据库表:
| 表名 | 描述 |
|---|---|
| android_metadata | 安卓元数据 |
| chat_friends | 聊天?私信? |
| record_best | 最佳记录 |
| record_details | 记录明细 |
| record_points | 记录点 |
以上最重要的就是 record_points 表,奇怪的是,app界面显示最早的数据是2014年,但是这个表里却没有。
果断按距离排序,找到了我那条心心念念的130多公里的数据了。
| 数据ID | 开始时间 | 结束时间 | 卡路里 | lat偏移 | lon偏移 | 距离 | 平均速度 | ... |
|---|---|---|---|---|---|---|---|---|
| 700 | 1460327870 | 1460377716 | 4792 | -0.003391 | 0.004833 | 135861.078125 | 11271.66015625 | ... |
对应记录ID为700的record_points数据也在。
格式为经纬度、高度、花费时间、速度和距离等字段。
接下来就是编程去导出数据,导出标准的gpx文件了。
导出数据-->GPX
鄙人用的C#熟练一些, 就直接找了现成的东西用了。
NuGet引用:
- Drapper ORM框架,直接拿数据
- Geo 处理GPX文件,支持读取和创建GPX格式文件
数据库工具:
- PDManner 元数建模 国产的数据库建模平台 元数建模
编码过程就不写了,直接上代码了,目前完成了
- 导出所有有记录点的轨迹,格式是yyyy-MM-dd_HH-mm-ss.gpx
- 运行时加入gpx文件完整路径名称,转换成GCJ-02格式并输出GCJ-02_yyyy-MM-dd_HH-mm-ss.gpx
RecordDetails模型类
点击查看代码 RecordDetails类
public partial class RecordDetails
{
/// <summary>
/// ;
/// </summary>
public int _Id { get; set; }
/// <summary>
/// ;
/// </summary>
public int Start_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int End_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Calorie { get; set; }
/// <summary>
/// ;
/// </summary>
public double Lat_Offset { get; set; }
/// <summary>
/// ;
/// </summary>
public double Lon_Offset { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Distance { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Avg_Speed { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Max_Speed { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Min_Speed { get; set; }
/// <summary>
/// ;
/// </summary>
public double Min_Altitude { get; set; }
/// <summary>
/// ;
/// </summary>
public double Max_Altitude { get; set; }
/// <summary>
/// ;
/// </summary>
public int Status { get; set; }
/// <summary>
/// ;
/// </summary>
public int Server_Id { get; set; }
/// <summary>
/// ;
/// </summary>
public int Last_Pause_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Total_Pause_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Duration { get; set; }
/// <summary>
/// ;
/// </summary>
public int Sport_Type { get; set; }
/// <summary>
/// ;
/// </summary>
public int Recordpoints_Count { get; set; }
/// <summary>
/// ;
/// </summary>
public int Last_Km_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Is_From_Server { get; set; }
/// <summary>
/// ;
/// </summary>
public int Source { get; set; }
/// <summary>
/// ;
/// </summary>
public string Device_Brand { get; set; }
/// <summary>
/// ;
/// </summary>
public string Device_Type { get; set; }
/// <summary>
/// ;
/// </summary>
public string Device_Sn { get; set; }
/// <summary>
/// ;
/// </summary>
public string Brand_Link { get; set; }
/// <summary>
/// ;
/// </summary>
public string Brand_Image { get; set; }
/// <summary>
/// ;
/// </summary>
public int Avg_Heart_Rate { get; set; }
/// <summary>
/// ;
/// </summary>
public int Max_Heart_Rate { get; set; }
/// <summary>
/// ;
/// </summary>
public int Min_Heart_Rate { get; set; }
/// <summary>
/// ;
/// </summary>
public int Avg_Slope { get; set; }
/// <summary>
/// ;
/// </summary>
public int Step_Count { get; set; }
/// <summary>
/// ;
/// </summary>
public string User_Id { get; set; }
/// <summary>
/// ;
/// </summary>
public int State { get; set; }
/// <summary>
/// ;
/// </summary>
public int Locationprivacy { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Goal_Distance { get; set; }
/// <summary>
/// ;
/// </summary>
public int Goal_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Goal_Continue { get; set; }
/// <summary>
/// ;
/// </summary>
public int Gps_Type { get; set; }
}
RecordPoints模型类
点击查看代码 RecordPoints类
public partial class RecordPoints
{
/// <summary>
/// ;
/// </summary>
public int _Id { get; set; }
/// <summary>
/// ;
/// </summary>
public int Recorddetail_Id { get; set; }
/// <summary>
/// ;
/// </summary>
public double Latitude { get; set; }
/// <summary>
/// ;
/// </summary>
public double Longitude { get; set; }
/// <summary>
/// ;
/// </summary>
public double Altitude { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Speed { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Accuracy { get; set; }
/// <summary>
/// ;
/// </summary>
public decimal Distance { get; set; }
/// <summary>
/// ;
/// </summary>
public int Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Heart_Rate { get; set; }
/// <summary>
/// ;
/// </summary>
public int Slope { get; set; }
/// <summary>
/// ;
/// </summary>
public int Used_Time { get; set; }
/// <summary>
/// ;
/// </summary>
public int Interrupt_Type { get; set; }
}
GPS坐标转换类 一开始用的是一个叫YaDong.GPS.Converter的NuGet包,结果发现转换的坐标怎么都不对,然后直接F12看源码怎么写的,当时已经检索了好几个写了算法的网页,发现就是抄的GitHub上一个古早的项目,结果还抄错了,改了别人的参数,还改反了,离了大普。。 特此说明,目前流传的最早坐标转换的算法 是 2013年GitHub的项目 :https://github.com/Leask/EvilTransform ,最早只有两个版本的代码,C#和Java的,上面项目Readme页面记录了最早来自 coodplex和googlecode,这两个代码托管平台已经打不开了。后面用的人最多的应该是 https://github.com/googollee/eviltransform ,包含了C语音版本,Python版本,Go语言版本,Php,Matlab,rush,swift等。
点击查看代码
//
// 摘要:
// GPS坐标系统类型
public enum GpsEnum
{
//
// 摘要:
// World Geodetic System 1984 国际上通用的GPS坐标系(地心坐标系) 例如: 普通GPS定位设备采集的原始坐标系
WGS84,
//
// 摘要:
// GCJ-02是由中国国家测绘局制订的地理信息系统的坐标系统 例如:腾讯地图、高德地图等
GCJ02,
//
// 摘要:
// 百度地图专用坐标系 例如: 百度地图
BD09,
//
// 摘要:
// 墨卡托坐标系 例如:ArcGis
Mercator
}
//
// 摘要:
// 通用GPS坐标点
public class GpsPoint
{
private static readonly double a = 6378245.0;
private static readonly double ee = 0.0066934216229659433;
private static readonly double bd_pi = 52.359877559829883;
//
// 摘要:
// 纬度
public double Latitude { get; set; }
//
// 摘要:
// 经度
public double Longitude { get; set; }
//
// 摘要:
// GPS坐标系统
public GpsEnum Type { get; set; }
//
// 摘要:
// 通用GPS坐标点构造函数
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// type:
// GPS坐标系统
public GpsPoint(double latitude, double longitude, GpsEnum type)
{
Latitude = latitude;
Longitude = longitude;
Type = type;
}
//
// 摘要:
// 获取WGS84的坐标点
//
// 返回结果:
// 转换后的位置信息
public GpsPoint GetWGS84()
{
switch( Type)
{
case GpsEnum.GCJ02:
return GCJ02_To_WGS84(Latitude, Longitude);
break;
case GpsEnum.BD09:
return BD09_To_WGS84(Latitude, Longitude);
break;
case GpsEnum.Mercator:
return Mercator_To_WGS84(Latitude, Longitude);
default: return null;
};
}
//
// 摘要:
// 获取GCJ02的坐标点
//
// 返回结果:
// 转换后的位置信息
public GpsPoint GetGCJ02()
{
switch (Type)
{
case GpsEnum.WGS84:
return WGS84_To_GCJ02(Latitude, Longitude);
break;
case GpsEnum.BD09:
return BD09_To_GCJ02(Latitude, Longitude);
break;
case GpsEnum.Mercator:
return Mercator_To_WGS84(Latitude, Longitude).GetGCJ02();
default: return null;
};
}
//
// 摘要:
// 获取BD09的坐标点
//
// 返回结果:
// 转换后的位置信息
public GpsPoint GetBD09()
{
switch (Type)
{
case GpsEnum.WGS84:
return WGS84_To_BD09(Latitude, Longitude);
break;
case GpsEnum.GCJ02:
return GCJ02_To_BD09(Latitude, Longitude);
break;
case GpsEnum.Mercator:
return Mercator_To_WGS84(Latitude, Longitude).GetBD09();
default: return null;
};
}
//
// 摘要:
// 获取墨卡托坐标
//
// 返回结果:
// 转换后的位置信息
public GpsPoint GetMercator()
{
switch(Type )
{
case GpsEnum.WGS84:
return WGS84_To_Mercator(Latitude, Longitude);
break;
case GpsEnum.GCJ02:
return GCJ02_To_WGS84(Latitude, Longitude).GetMercator();
case GpsEnum.BD09:
return BD09_To_WGS84(Latitude, Longitude).GetMercator();
default: return null;
};
}
//
// 摘要:
// 是否超出中国境内
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// bool
private static bool OutOfChina(double latitude, double longitude)
{
if (longitude < 72.004 || longitude > 137.8347)
{
return true;
}
if (latitude < 0.8293 || latitude > 55.8271)
{
return true;
}
return false;
}
private static double TransformLat(double latitude, double longitude)
{
double num = -100.0 + 2.0 * latitude + 3.0 * longitude + 0.2 * longitude * longitude + 0.1 * longitude * latitude + 0.2 * Math.Sqrt(Math.Abs(latitude));
num += (20.0 * Math.Sin(6.0 * latitude * Math.PI) + 20.0 * Math.Sin(2.0 * latitude * Math.PI)) * 2.0 / 3.0;
num += (20.0 * Math.Sin(longitude * Math.PI) + 40.0 * Math.Sin(longitude / 3.0 * Math.PI)) * 2.0 / 3.0;
return num + (160.0 * Math.Sin(longitude / 12.0 * Math.PI) + 320.0 * Math.Sin(longitude * Math.PI / 30.0)) * 2.0 / 3.0;
}
private static double TransformLon(double latitude, double longitude)
{
double num = 300.0 + latitude + 2.0 * longitude + 0.1 * latitude * latitude + 0.1 * longitude * latitude + 0.1 * Math.Sqrt(Math.Abs(latitude));
num += (20.0 * Math.Sin(6.0 * latitude * Math.PI) + 20.0 * Math.Sin(2.0 * latitude * Math.PI)) * 2.0 / 3.0;
num += (20.0 * Math.Sin(latitude * Math.PI) + 40.0 * Math.Sin(latitude / 3.0 * Math.PI)) * 2.0 / 3.0;
return num + (150.0 * Math.Sin(latitude / 12.0 * Math.PI) + 300.0 * Math.Sin(latitude / 30.0 * Math.PI)) * 2.0 / 3.0;
}
//
// 摘要:
// 国际通用坐标系 (WGS84) to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint WGS84_To_GCJ02(double latitude, double longitude)
{
double num = TransformLat(longitude - 105.0, latitude - 35.0);
double num2 = TransformLon(longitude - 105.0, latitude - 35.0);
double d = latitude / 180.0 * Math.PI;
double num3 = Math.Sin(d);
num3 = 1.0 - ee * num3 * num3;
double num4 = Math.Sqrt(num3);
num = num * 180.0 / (a * (1.0 - ee) / (num3 * num4) * Math.PI);
num2 = num2 * 180.0 / (a / num4 * Math.Cos(d) * Math.PI);
double latitude2 = latitude + num;
double longitude2 = longitude + num2;
return new GpsPoint(latitude2, longitude2, GpsEnum.GCJ02);
}
//
// 摘要:
// 火星坐标系 (GCJ-02) to 国际通用坐标系 (WGS84) Mars Geodetic System ==> World Geodetic System
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint GCJ02_To_WGS84(double latitude, double longitude)
{
double num = TransformLat(longitude - 105.0, latitude - 35.0);
double num2 = TransformLon(longitude - 105.0, latitude - 35.0);
double d = latitude / 180.0 * Math.PI;
double num3 = Math.Sin(d);
num3 = 1.0 - ee * num3 * num3;
double num4 = Math.Sqrt(num3);
num = num * 180.0 / (a * (1.0 - ee) / (num3 * num4) * Math.PI);
num2 = num2 * 180.0 / (a / num4 * Math.Cos(d) * Math.PI);
double num5 = latitude + num;
double num6 = longitude + num2;
return new GpsPoint(latitude * 2.0 - num5, longitude * 2.0 - num6, GpsEnum.WGS84);
}
//
// 摘要:
// 火星坐标系 (GCJ-02) to 百度坐标系 (BD-09)
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint GCJ02_To_BD09(double latitude, double longitude)
{
double num = Math.Sqrt(longitude * longitude + latitude * latitude) + 2E-05 * Math.Sin(latitude * bd_pi);
double d = Math.Atan2(latitude, longitude) + 3E-06 * Math.Cos(longitude * bd_pi);
double longitude2 = num * Math.Cos(d) + 0.0065;
double latitude2 = num * Math.Sin(d) + 0.006;
return new GpsPoint(latitude2, longitude2, GpsEnum.BD09);
}
//
// 摘要:
// 火星坐标系 (GCJ-02) to 百度坐标系 (BD-09)
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint BD09_To_GCJ02(double latitude, double longitude)
{
double num = longitude - 0.0065;
double num2 = latitude - 0.006;
double num3 = Math.Sqrt(num * num + num2 * num2) - 2E-05 * Math.Sin(num2 * bd_pi);
double d = Math.Atan2(num2, num) - 3E-06 * Math.Cos(num * bd_pi);
double longitude2 = num3 * Math.Cos(d);
double latitude2 = num3 * Math.Sin(d);
return new GpsPoint(latitude2, longitude2, GpsEnum.GCJ02);
}
//
// 摘要:
// 百度坐标系 (BD-09) to 国际通用坐标系 (WGS84)
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint BD09_To_WGS84(double latitude, double longitude)
{
GpsPoint gpsPoint = BD09_To_GCJ02(latitude, longitude);
return GCJ02_To_WGS84(gpsPoint.Latitude, gpsPoint.Longitude);
}
//
// 摘要:
// 国际通用坐标系 (WGS84) to 百度坐标系 (BD-09)
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint WGS84_To_BD09(double latitude, double longitude)
{
GpsPoint gpsPoint = WGS84_To_GCJ02(latitude, longitude);
return GCJ02_To_BD09(gpsPoint.Latitude, gpsPoint.Longitude);
}
//
// 摘要:
// MercatorToWGS84 墨卡托转WGS84
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint Mercator_To_WGS84(double latitude, double longitude)
{
latitude /= 3606751501.2;
longitude /= 3606751501.2;
latitude = 180.0 / Math.PI * (2.0 * Math.Atan(Math.Exp(latitude * Math.PI / 180.0)) - Math.PI / 2.0);
return new GpsPoint(latitude, longitude, GpsEnum.WGS84);
}
//
// 摘要:
// WGS84ToMercator WGS84转墨卡托
//
// 参数:
// latitude:
// 纬度
//
// longitude:
// 经度
//
// 返回结果:
// 转换后的位置信息
public static GpsPoint WGS84_To_Mercator(double latitude, double longitude)
{
longitude *= 111319.49077777777;
latitude = Math.Log(Math.Tan((90.0 + latitude) * Math.PI / 360.0)) / (Math.PI / 180.0);
latitude *= 111319.49077777777;
return new GpsPoint(latitude, longitude, GpsEnum.Mercator);
}
}
由于用的是控制台程序,简单粗暴,直接加载Cearch.db,按返回的记录表循环获取轨迹点记录就行了。
Program类
点击查看代码
internal class Program
{
public static string conn = @"Data Source=C:\Users\john\Desktop\MouseWithoutBorders\Cearch.db;";
static void Main(string[] args)
{
GpsPoint point = new GpsPoint(31.1774276,121.5272106,GpsEnum.WGS84);//测试坐标,通过对比高德的坐标转换API看结果,经过高德API的对比,基本上到了点后第五位相同,部分坐标第6位也相同
var newPoint = point.GetGCJ02();
Console.WriteLine(newPoint.Latitude+" "+newPoint.Longitude);
if(args.Length > 0 )
{
var sourceGpx = args[0];
Console.WriteLine("正在读取gpx文件:"+sourceGpx);
if(sourceGpx != null ) {
if (!sourceGpx.Contains(".gpx"))
{
Console.WriteLine("请输入gpx文件名称!");
Console.ReadKey();
return;
}
if(File.Exists(sourceGpx))
{
GPXConverWCGtoGCJ(sourceGpx);
Console.WriteLine("转换成功!输出文件为:GCJ_02_"+sourceGpx);
Console.ReadKey();
return;
}
else
{
Console.WriteLine($"文件{sourceGpx}不存在!");
Console.ReadKey();
}
}
Console.WriteLine("输入参数为空!");
Console.ReadKey();
return;
}
Dictionary<RecordDetails, List<RecordPoints>> records = new Dictionary<RecordDetails, List<RecordPoints>>();
var items = GetAllRecordDetails();
Console.WriteLine($"总找到{items.Count}条数据。");
Console.WriteLine("前十条数据为:");
//foreach(var item in items.Take(10) )
foreach(var item in items.Take(1000))
{
//Console.WriteLine($"{item._Id},开始时间:{DateTimeOffset.FromUnixTimeSeconds(item.Start_Time).ToLocalTime().ToString("g")},距离 {item.Distance} 米。用时 {new TimeSpan(0,0,item.Duration).ToString(@"hh\:mm\:ss")} ");
var points = GetRecordPointsByDetailId(item._Id);
if(points.Count > 0 )
{
//Console.WriteLine($"获取到轨迹点 {points.Count} 个。");
records.Add(item, points);
}
}
Console.WriteLine($"包含轨迹点的记录条数 {records.Keys.Count}.");
foreach (var key in records.Keys)
{
var points = records[key];
GpsData gpsData = new GpsData();
var recordTime = DateTimeOffset.FromUnixTimeSeconds(key.Start_Time).ToLocalTime().DateTime;
gpsData.Tracks.Add(new Track());
gpsData.Tracks[0].Segments.Add(new TrackSegment());
foreach (var record in points)
{
//Gpx11Serializer gpx11Serializer = new Gpx11Serializer();
//gpsData.Waypoints.Add(new Waypoint(record.Latitude, record.Longitude, record.Altitude, recordTime.AddSeconds(record.Time)));
//gpsData.Tracks[0].Segments[0].Waypoints.Add(new Waypoint(record.Latitude, record.Longitude, record.Altitude, recordTime.AddSeconds(record.Time)));
//用GCJ-02格式输出
point = new GpsPoint(record.Latitude, record.Longitude, GpsEnum.WGS84);
newPoint = point.GetGCJ02();
gpsData.Tracks[0].Segments[0].Waypoints.Add(new Waypoint(newPoint.Latitude, newPoint.Longitude, record.Altitude, recordTime.AddSeconds(record.Time)));
//gpx11Serializer.Serialize(gpsData);
}
string content = gpsData.ToGpx(2);
using (FileStream fs = new FileStream(recordTime.ToString("GCJ_yyyy-MM-dd_HH-mm-ss") + ".gpx", FileMode.OpenOrCreate, FileAccess.Write))
{
byte[] buffer = Encoding.UTF8.GetBytes(content);
fs.Write(buffer, 0, buffer.Length);
}
}
Console.ReadLine();
}
public static List<RecordDetails> GetAllRecordDetails()
{
using (IDbConnection cnn = new SQLiteConnection(conn))
{
cnn.Open();
//var output = cnn.Query<RecordDetails>("select * from Record_Details ORDER BY distance desc LIMIT 10").ToList();
var output = cnn.Query<RecordDetails>("select * from Record_Details ORDER BY distance desc").ToList();
return output.ToList();
}
}
public static List<RecordPoints> GetRecordPointsByDetailId(int detailId)
{
using (IDbConnection cnn = new SQLiteConnection(conn))
{
cnn.Open();
//var output = cnn.Query<RecordDetails>("select * from Record_Details ORDER BY distance desc LIMIT 10").ToList();
var output = cnn.Query<RecordPoints>("select * from record_points where recorddetail_id = "+detailId+" ORDER BY time").ToList();
return output.ToList();
}
}
public static void GPXConverWCGtoGCJ(string pathGpx)
{
//var gpxFileStr = File.ReadAllText(pathGpx);
GpsData gpxData = new GpsData();
using(FileStream fs = new FileStream(pathGpx, FileMode.Open, FileAccess.Read))
{
Gpx11Serializer gpx11Serializer = new Gpx11Serializer();
gpxData = gpx11Serializer.DeSerialize(new StreamWrapper(fs));
}
foreach (var wcgPoint in gpxData.Tracks[0].Segments[0].Waypoints)
{
GpsPoint point = new GpsPoint(wcgPoint.Coordinate.Latitude, wcgPoint.Coordinate.Longitude, GpsEnum.WGS84);
point = point.GetGCJ02();
wcgPoint.Point = new Geo.Geometries.Point(point.Latitude, point.Longitude);
}
string content = gpxData.ToGpx(2);
using (FileStream fs = new FileStream("GCJ-02_"+pathGpx, FileMode.OpenOrCreate, FileAccess.Write))
{
byte[] buffer = Encoding.UTF8.GetBytes(content);
fs.Write(buffer, 0, buffer.Length);
}
}
}
参考资料
无Root修改应用内部存储数据
利用adb备份app的数据
ADB读取和备份安卓应用数据(无Root)
解密备份出来的ab文件工具,abe
制作轨迹点叠加地图视频
telemetry-overlay(收费,大概1k人名币)
佳明Virb编辑器 已经停止更新了,最新的是18年发布的,无法加载地图
gpx2video C项目 未测试
版本最全的坐标转换
github上流传最早的坐标转换版本
Dapper
Geo

浙公网安备 33010602011771号