基于flutter_map的导航应用:如何隐藏Polyline已行驶路段
Flutter导航Polyline随用户移动动态截断的问题解决
我基于flutter_map、routing_client_dart和OpenStreetMap开发导航应用,已经实现实时位置监听,但在动态截断Polyline(移除已行驶路段)时遇到了问题:使用截取子列表的方法会导致Polyline超前或滞后于用户位置。
原始Polyline显示代码:
PolylineLayer( polylines: [ Polyline( points: mapsServices.road!.polyline! .map((point) =>LatLng(point.lat, point.lng)).toList(), color: Colors.blue, strokeWidth: 8, borderStrokeWidth: 3, borderColor: Colors.black.withValues(alpha: 0.3), ), ], ),
尝试的截断代码(效果不符合预期):
List<LngLat> updatePolyline(LatLng currentLocation) { if (road == null || road!.polyline == null) return []; List<LngLat> polylinePointsLngLat = road!.polyline!; List<LatLng> polylinePoints = polylinePointsLngLat .map((LngLat lngLat) => LatLng(lngLat.lat, lngLat.lng)) .toList(); bool isUserOnPath = manager.isOnPath(road!, currentLocation.toLngLat(), tolerance: 10); if (isUserOnPath) { LatLng closestPoint = findClosestPoint(currentLocation, polylinePoints); int index = polylinePoints.indexOf(closestPoint); if (index != -1) { List<LngLat> updatedPolyline = polylinePointsLngLat.sublist(index); updatedPolyline.insert(0, currentLocation.toLngLat()); return updatedPolyline; } } return polylinePointsLngLat; } LatLng findClosestPoint(LatLng userLocation, List<LatLng> polyline) { final Distance distance = Distance(); LatLng closestPoint = polyline.first; double minDistance = distance(userLocation, polyline.first); for (var point in polyline) { double dist = distance(userLocation, point); if (dist < minDistance) { minDistance = dist; closestPoint = point; } } return closestPoint; } List<LatLng> trimPolyline(List<LatLng> polyline, LatLng userLocation) { LatLng closestPoint = findClosestPoint(userLocation, polyline); int index = polyline.indexOf(closestPoint); if (index != -1) { return polyline.sublist(index); } return polyline; }
原始代码问题分析
- 仅匹配离散点:
findClosestPoint只寻找Polyline上距离用户最近的原始节点,而用户实际位置往往在两个节点之间的线段上,直接取节点索引截断必然出现偏差。 - 忽略行驶方向:如果用户短暂偏离路线后返回,可能匹配到路径后方的节点,导致错误截断已行驶路段。
- 破坏路径连续性:直接将用户位置插入Polyline头部,会导致路径出现突兀的转折,影响视觉效果。
修正方案:基于线段投影与累积距离的精准截断
通过计算用户在路径上的投影位置和前进距离,实现精准的Polyline截断:
1. 核心工具函数:计算用户在路径上的前进距离
import 'package:latlong2/latlong.dart'; double calculateProgressDistance(LatLng userLocation, List<LatLng> polyline) { double totalDistance = 0.0; final Distance distance = Distance(); for (int i = 0; i < polyline.length - 1; i++) { final segmentStart = polyline[i]; final segmentEnd = polyline[i + 1]; // 计算用户到当前线段的投影点 final projection = distance.projectOnSegment(userLocation, segmentStart, segmentEnd); if (projection.isOnSegment) { // 返回起点到投影点的累积距离 return totalDistance + distance(segmentStart, projection.projectedPoint); } totalDistance += distance(segmentStart, segmentEnd); } // 用户已到达或超出终点,返回总路径长度 return totalDistance; }
2. 优化后的Polyline更新函数
List<LngLat> updatePolyline(LatLng currentLocation) { if (road == null || road!.polyline == null) return []; final List<LngLat> originalLngLat = road!.polyline!; final List<LatLng> originalPolyline = originalLngLat .map((lngLat) => LatLng(lngLat.lat, lngLat.lng)) .toList(); bool isUserOnPath = manager.isOnPath(road!, currentLocation.toLngLat(), tolerance: 10); if (!isUserOnPath) return originalLngLat; final double userProgress = calculateProgressDistance(currentLocation, originalPolyline); double accumulatedDistance = 0.0; final Distance distance = Distance(); for (int i = 0; i < originalPolyline.length - 1; i++) { final segmentStart = originalPolyline[i]; final segmentEnd = originalPolyline[i + 1]; final segmentLength = distance(segmentStart, segmentEnd); if (accumulatedDistance + segmentLength >= userProgress) { // 计算线段上的截断点 final remaining = userProgress - accumulatedDistance; final truncatedPoint = distance.offset(segmentStart, remaining, distance.bearing(segmentStart, segmentEnd)); // 构建连续的新路径:当前位置 → 截断点 → 剩余路径 final newPolyline = [ currentLocation, truncatedPoint, ...originalPolyline.sublist(i + 1), ]; return newPolyline.map((latLng) => LngLat(latLng.lng, latLng.lat)).toList(); } accumulatedDistance += segmentLength; } // 用户到达终点,仅保留当前位置 return [currentLocation.toLngLat()]; }
3. 调用方式
在位置更新回调中更新Polyline数据,刷新UI:
void onLocationUpdated(LatLng newLocation) { setState(() { _updatedPolyline = updatePolyline(newLocation); }); } // 绘制更新后的Polyline PolylineLayer( polylines: [ Polyline( points: _updatedPolyline.map((p) => LatLng(p.lat, p.lng)).toList(), color: Colors.blue, strokeWidth: 8, borderStrokeWidth: 3, borderColor: Colors.black.withAlpha(30), ), ], ),
优化效果
- 精准匹配位置:通过线段投影计算用户在路径上的真实位置,避免离散点匹配的偏差。
- 方向感知:基于累积前进距离判断截断点,不会因短暂偏离路线导致错误截断。
- 路径连续流畅:连接用户位置与截断点,保证Polyline视觉上的连贯性。
内容的提问来源于stack exchange,提问作者Jerry Matera
相关产品推荐
相关产品推荐

