65.9K
CodeProject 正在变化。 阅读更多。
Home

Bernie 的 Trackviewer

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (27投票s)

2010年8月23日

CPOL

7分钟阅读

viewsIcon

64033

downloadIcon

4270

在带有在线地图和鸟瞰图的精美 GUI 上查看和编辑您的 GPS 轨迹记录。

当前(更新的)1.5 版的可执行文件和源代码可从 http://berniestrackviewer.codeplex.com/ [^] 下载。

引言

市面上有很多工具可以用来查看 GPS 设备记录的轨迹。它们通常功能强大,但编辑功能却相当少见。编辑有很多充分的理由,例如,您可能只想发布轨迹的一部分,需要纠正一些错位的点,或者想移除在施肥时短暂偏离到灌木丛中的轨迹……如果您想为 OpenStreetMap [^] 添加数据,建议每秒记录一个点以获得平滑的弯道,然后移除直线路段上不必要的点。

因此,我决定编写自己的 GPX 文件分析和编辑软件。在此,我想介绍开发过程中的一些步骤和一个小型示例程序。

GPX 格式

此格式由 TopoGrafix 开发,他们发布了相应的 XML 模式(请参见 http://www.topografix.com/GPX/1/1/gpx.xsd [^])。它显示了一种分层结构

Structure of GPX data

GPX 本身中的 `WayPoint` 是一些“兴趣点”,您可以在设备上显式保存。`RoutePoint` 和 `TrackPoint` 是同一种类型,但它们分别属于 `Route` 和 `Track`。轨迹使用一个额外的层,“`TrackSegment`”。文档说明,在 GPS 信号丢失或 GPS 接收器关闭的地方,应该为每个连续的轨迹数据段启动一个新的 `TrackSegment`。关于这一点是否仍然有用,存在一些讨论。

现在我们需要一种方法来获取 C# 类。Windows SDK 中包含的 `xsd.exe`(可以在 *C:\Program Files (x86)\Microsoft SDKs\Windows\v<Version>\Bin\* 或其子文件夹中找到)。(以前,它随 Visual Studio 一起提供,并安装在 *C:\Program Files (x86)\Microsoft Visual Studio <Version>\SDK\v<Version>\Bin*)。我们将模式从浏览器保存到本地文件,然后调用 `xsd`。

xsd.exe D:\Temp\gpx.xsd /classes /out:D:\Temp /language:CS

就这样,一个包含 GPX 文件所需所有类的庞大的 C# 代码文件就生成了。

一些属性名称看起来相当难看——例如,public decimal ele。我更希望在这里使用一个易读的名称:Elevation。如果我们重命名它,序列化/反序列化将不兼容。但有一个技巧——XmlElementAttribute。这样我们就可以告诉序列化器属性如何映射到 XML 元素。

[System.Xml.Serialization.XmlElementAttribute("ele")]
public decimal Elevation

我们还将 TopoGrafix 网站上的文档作为代码注释添加进去。进一步的编辑涉及类名的模糊(例如,wptType -> WayPoint),以及对于编辑目的而言,泛型列表比数组更好。

现在,我们有了一些漂亮的类,它们只是数据容器——它们本身没有功能。让我们添加一些功能,例如用于读写 GPX 文件。

public static GPXType FromFile(string fileName)
public void ToFile(string fileName)

当我们想向航点添加更多属性时,例如速度,我们必须考虑到 XML 序列化器会将此值写入文件——这可能会导致其他设备无法读取。我们可以使用两个技巧。

  • 使用函数而不是属性,例如,使用 double GetSpeed() 而不是 double Speed(私有成员变量 `_Speed` 被序列化器忽略)。
  • 使用 `XmlIgnoreAttribute` 特性。

我希望自动生成的类因此可以变得更易于理解和更有用。

海拔的怪癖

从卫星确定海拔并不好。现代 GPS 接收器还配备了气压计。它们通常使用气压计的读数,但时不时地会用卫星读数进行校准。由于没有记录关于此校准的信息,因此您无法知道何时发生以及从那时起海拔读数改变了多少。海拔图可能完全无用。

我决定关闭自动校准,然后发现与预期值存在系统性偏差。例如,我哥哥家的位置比预期高 10 米。经过大量网络搜索,我找到了主要原因:气温(另请参阅“Grundlagen - Luft + Luftdruck”;链接已删除,原始页面不再可用,重定向指向垃圾邮件)。气压计使用气压到海拔的转换因子,约为每 100 米 12 百帕——这对于 15°C 或 288 K(开尔文)是有效的。在当时大约 -10°C 的低温下,我家和我哥哥家之间的海拔差从 100 米增加到 110 米 = 100 米 * 288K / 263K。

另一个问题是存在小的振荡,通常小于一米。在计算总爬升/下降时,这些振荡可能会累积到几米,并严重扭曲平原轨迹的结果。在山区,也可能报告不准确的值。我添加了一个设置,用于计算爬升/下降所需的与前一个点的最小距离。

时间戳问题

全球定位系统实际上依赖于极其精确的时间值。因此,我们应该认为我们的航点的时间戳是完美的。但事实并非如此。我发现了两个案例,其中一个较晚的航点比其前一个点的时间戳更早——我在 Lounge 中发布了其中一个案例(时间旅行证明[^])。

这可能是我的 Garmin Oregon 时钟问题造成的,但我没有在网上找到相关信息。另一种原因可能是美国军方(GPS 的所有者)故意进行干扰,但据说“选择性可用性”已经关闭。

示例应用程序 

示例应用程序需要 .NET Framework 2。对于地图和航拍照片,需要高速互联网连接。

只需下载文件并将存档解压缩到一个文件夹中。然后编辑配置文件(*BerniesTrackViewer.exe.config*)——您应该为缓存航拍照片和地图的文件夹以及显示图像的文件名输入有效数据。

现在双击可执行文件,并将 GPX 文件拖入其中,选择要编辑的轨迹和轨迹段,然后转到“编辑轨迹”以各种形式显示轨迹。双击一个点进行编辑,拖动它(右键单击)到另一个位置,校正所有点的高度等,最后从主页面保存您的工作。

进一步开发

基本类工作得相当好,因此开发将集中在“示例应用程序”上。

  • 总爬升/下降的算法需要改进
  • 一次显示/编辑多个轨迹段
  • 在单核计算机上加载地图瓦片有时似乎会挂起(即,加载了一两个瓦片,一分钟内没有任何反应,然后突然显示了更多瓦片)
  • 许多设置实际上是用户设置,但仍存储在应用程序配置文件中——这里需要进行一些区分。
  • 撤销/重做功能
  • 添加安装程序(因为配置问题)
  • 使应用程序更健壮(防错)…… 

我不知道我什么时候会有时间来做这些…… 

致谢 / 许可

此示例应用程序使用了 CodeProject 上发布的几位作者的代码。

对于这些部分,它们的许可协议可能适用。对于我的工作部分,适用的是 CodeProject 公共许可证(^)。

历史

版本 1.1:2010 年 9 月 15 日

  • 添加了照片映射功能

版本 1.2:2011 年 1 月 9 日

  • 主页用户界面新设计
  • 还显示了不属于轨迹的航点
  • 可以将路线转换为轨迹
  • 可以设置缓存地图的最大年龄

版本 1.3:2011 年 2 月 13 日

  • 通过移除不必要的点来压缩轨迹段
  • 进一步增强用户界面

版本 1.4:2013 年 9 月 8 日

  • 添加了 Garmin 扩展,用于心率等
  • 改进了可用性:自动以地图/航拍图像作为背景打开第一个轨迹段(可配置)

版本 1.5:2016 年 6 月 12 日

  • 由于气压计不太精确,在与直接前一个航点计算时,爬升/下降计算可能相当不准确。现在,可以指定航点之间的最小距离,并将搜索前一个航点,直到达到该距离。
© . All rights reserved.