如何基于串口数据实时向List<PointLatLng>添加点实现GMap.NET轨迹追踪?
解决GMap.NET实时追踪物体轨迹的问题
你的问题核心在于每次接收串口数据时都重新创建了轨迹列表和路由对象,导致旧的点被丢弃,始终只显示最新的单个点。下面给你梳理下正确的实现思路和代码:
关键思路
要实时更新轨迹,你需要:
- 将轨迹点列表、GMapOverlay和GMapRoute作为类的成员变量(而非局部变量),这样每次接收数据时能复用同一个对象,保留历史点
- 收到新坐标时,直接往已有的点列表里添加,然后通知GMap.NET更新路由并刷新控件
- 注意线程安全:串口接收事件在后台线程触发,更新UI控件时要回到UI线程
修改后的代码示例
首先在窗体类中定义成员变量:
// 全局保存轨迹点、图层和路线对象 private List<PointLatLng> _trajectoryPoints = new List<PointLatLng>(); private GMapOverlay _traceOverlay; private GMapRoute _carRoute;
然后在窗体加载(或初始化)方法中完成基础设置:
private void Form_Load(object sender, EventArgs e) { // 初始化轨迹图层 _traceOverlay = new GMapOverlay("Real Time Position"); // 初始化路线,绑定我们的轨迹点列表 _carRoute = new GMapRoute(_trajectoryPoints, "Trajectory"); _carRoute.Stroke = new Pen(Color.Red, 3); // 将路线添加到图层,再把图层添加到地图控件 _traceOverlay.Routes.Add(_carRoute); gMapControl1.Overlays.Add(_traceOverlay); }
接下来在串口数据接收的事件处理方法中更新轨迹:
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { // 这里省略解析GPS_Latitude和GPS_Longitude的代码,假设已获取到有效坐标 double GPS_Latitude = ...; // 实际解析得到的纬度 double GPS_Longitude = ...; // 实际解析得到的经度 var newPoint = new PointLatLng(GPS_Latitude, GPS_Longitude); // 跨线程更新UI,避免线程安全问题 if (gMapControl1.InvokeRequired) { gMapControl1.Invoke(new Action(() => UpdateTrajectory(newPoint))); } else { UpdateTrajectory(newPoint); } } // 封装更新轨迹的方法 private void UpdateTrajectory(PointLatLng newPoint) { // 添加新点到轨迹列表 _trajectoryPoints.Add(newPoint); // 通知GMap.NET路线已更新 _carRoute.UpdateLocalPosition(); // 刷新地图控件显示最新轨迹 gMapControl1.Refresh(); }
为什么你的原有代码不行?
你之前的代码每次接收数据时,都会重新创建coordinates列表、GMapRoute和GMapOverlay,相当于每次都在地图上添加一条只有当前点的新路线,而旧的路线可能还留在地图上(或者被覆盖),看起来就始终只有一个点。复用同一个点列表和路由对象后,所有历史点都会被保留,轨迹会持续延伸。
内容的提问来源于stack exchange,提问作者Okenite




