如何在Google Directions API中优化路线折线的平滑度?
提升Google Directions API折线平滑度的方法
问题描述
我需要在地图上显示更平滑的折线(当前折线存在尖锐拐点),注意到Routes Preferred API支持polylineQuality":"HIGH_QUALITY"参数,但Google Directions API没有这个选项,请问有什么办法可以提升折线的平滑度?
原有实现代码:
import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:google_maps_flutter/google_maps_flutter.dart'; class Routing { Future<List<LatLng>> getPolylinePoints( LatLng source, LatLng destination) async { String apiKey = "API_KEY"; String polylineQuality = "HIGH_QUALITY"; String baseUrl = "https://maps.googleapis.com/maps/api/directions/json?"; String url = "$baseUrl" "origin=${source.latitude},${source.longitude}&" "destination=${destination.latitude},${destination.longitude}&" "key=$apiKey&" "polylineQuality=$polylineQuality"; var response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { var jsonData = jsonDecode(response.body); var points = jsonData['routes'][0]['overview_polyline']['points']; return decodePolyline(points); } else { throw Exception("Failed to load directions"); } } List<LatLng> decodePolyline(String polyline) { List<LatLng> points = []; int index = 0; int len = polyline.length; int lat = 0; int lng = 0; while (index < len) { int b; int shift = 0; int result = 0; do { b = polyline.codeUnitAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lat += dlat; shift = 0; result = 0; do { b = polyline.codeUnitAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lng += dlng; LatLng p = LatLng((lat / 1E5).toDouble(), (lng / 1E5).toDouble()); points.add(p); } return points; } }
解决方案
方法一:改用Routes Preferred API
直接切换到支持polylineQuality参数的Routes Preferred API,该API返回的折线本身具备更高平滑度。修改代码如下:
Future<List<LatLng>> getPolylinePoints( LatLng source, LatLng destination) async { String apiKey = "API_KEY"; String baseUrl = "https://routes.googleapis.com/directions/v2:computeRoutes"; // 构造POST请求体 var requestBody = jsonEncode({ "origin": { "location": { "latLng": { "latitude": source.latitude, "longitude": source.longitude } } }, "destination": { "location": { "latLng": { "latitude": destination.latitude, "longitude": destination.longitude } } }, "travelMode": "DRIVE", "polylineQuality": "HIGH_QUALITY", "polylineEncoding": "ENCODED_POLYLINE" }); var response = await http.post( Uri.parse(baseUrl), headers: { "Content-Type": "application/json", "X-Goog-Api-Key": apiKey, "X-Goog-FieldMask": "routes.polyline" }, body: requestBody, ); if (response.statusCode == 200) { var jsonData = jsonDecode(response.body); var points = jsonData['routes'][0]['polyline']['encodedPolyline']; return decodePolyline(points); } else { throw Exception("Failed to load directions: ${response.body}"); } }
注意:Routes Preferred API为付费服务,需确保API密钥已开通对应权限,请求方式为POST,需指定字段掩码。
方法二:客户端折线平滑处理
若不想切换API,可在客户端对Directions API返回的折线点做平滑处理,以下是简单的贝塞尔曲线平滑实现:
在Routing类中添加平滑函数:
List<LatLng> smoothPolyline(List<LatLng> points) { if (points.length < 3) return points; List<LatLng> smoothed = []; smoothed.add(points[0]); for (int i = 1; i < points.length - 1; i++) { LatLng p0 = points[i - 1]; LatLng p1 = points[i]; LatLng p2 = points[i + 1]; // 计算中间控制点 double midLat1 = (p0.latitude + p1.latitude) / 2; double midLng1 = (p0.longitude + p1.longitude) / 2; double midLat2 = (p1.latitude + p2.latitude) / 2; double midLng2 = (p1.longitude + p2.longitude) / 2; smoothed.add(LatLng(midLat1, midLng1)); smoothed.add(LatLng(midLat2, midLng2)); } smoothed.add(points.last); return smoothed; }
在获取原始折线点后调用该函数:
// 在getPolylinePoints的返回逻辑中修改 List<LatLng> rawPoints = decodePolyline(points); return smoothPolyline(rawPoints);
也可使用第三方库(如flutter_map_polyline_smoother)简化实现。
方法三:获取详细路径点
Directions API的overview_polyline是简化折线,而legs下的steps包含更密集的路径点,合并所有steps的polyline可提升视觉平滑度:
修改getPolylinePoints中的解析逻辑:
if (response.statusCode == 200) { var jsonData = jsonDecode(response.body); List<LatLng> allPoints = []; // 遍历所有legs和steps,合并路径点 for (var leg in jsonData['routes'][0]['legs']) { for (var step in leg['steps']) { String stepPolyline = step['polyline']['points']; allPoints.addAll(decodePolyline(stepPolyline)); } } return allPoints; }
该方法得到的点集更密集,拐点更自然,可结合方法二进一步优化。
内容的提问来源于stack exchange,提问作者m.altinisik
相关产品推荐
相关产品推荐

