iOS解决百度地图驾车导航画线不显示
背景:公司需要做驾车导航路径,选好起点、终点,然后把途经点选好,调用百度地图的规划api,得到所有的点,然后在地图上展示出来。页面上有个导航按钮,一点导航就开始导航了。
问题:基础版本的地图,请求驾车路径规划,路径也画到了地图上,然而将地图升级成导航地图,请求导航路径规划,却画线失败,无法展示路径,几经周折终于搞定了。
解决:通过两个版本的对比发现:
1、基础版本得到的点不是直接的经纬度,是比较大的两个数字,百度地图API的备注是“地理坐标点,用直角地理坐标表示”。
2、导航地图版本得到的是我们平时理解的经纬度。
结论:不同的数据列表初始化线路需要调用不同的函数。而我一直用地理坐标点数组初始化函数画线,这是画线不显示的主要问题。
3、还遇到了线路画偏的情况,进行坐标转后再画线就正常了。
下面是两个版本的大部分代码,希望给用的到同学有帮助。
A、基础版驾车线路规划请求
lazy var routeSearch:BMKRouteSearch = {
let search = BMKRouteSearch()
search.delegate = self
return search
}()
func drivingSearchV1() { guard let staIt = startItem else { return } guard let endIt = endItem else { return } /* 线路检索节点信息类,一个路线检索节点可以通过经纬度坐标或城市名加地名确定 实例化线路检索节点信息类对象 */ let start = BMKPlanNode() //起点名称 start.name = staIt.address start.pt = staIt.coordinate() // 途经点 var plist = [BMKPlanNode]() for item in list { let start = BMKPlanNode() //起点名称 start.name = item.nodeName //起点所在城市,注:cityName和cityID同时指定时,优先使用cityID start.pt = CLLocationCoordinate2D(latitude: item.latitude.doubleValue, longitude: item.longitude.doubleValue) plist.append(start) } //实例化线路检索节点信息类对象 let end = BMKPlanNode() //终点名称 end.name = endIt.address end.pt = endIt.coordinate() //初始化请求参数类BMKDrivingRoutePlanOption的实例 let drivingRoutePlanOption = BMKDrivingRoutePlanOption() //检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID drivingRoutePlanOption.from = start //检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID drivingRoutePlanOption.to = end drivingRoutePlanOption.wayPointsArray = plist /** 发起驾乘路线检索请求,异步函数,返回结果在BMKRouteSearchDelegate的onGetDrivingRouteResult中 */ let flag = routeSearch.drivingSearch(drivingRoutePlanOption) if flag { print("驾车检索成功") var points = [VmPointAnnotation]() for (k,item) in list.enumerated() { let coord = CLLocationCoordinate2D(latitude:item.latitude.doubleValue, longitude: item.longitude.doubleValue) if !CLLocationCoordinate2DIsValid(coord) || coord.longitude == 0 || coord.latitude == 0 { continue } //初始化标注类BMKPointAnnotation的实例 let annotation = VmPointAnnotation.init() //设置标注的经纬度坐标 annotation.coordinate = coord //设置标注的标题 annotation.title = item.vmCode //副标题 annotation.subtitle = String(k + 1) + ":" + item.nodeName annotation.vm = item points.append(annotation) } let sta = StaEndPointAnnotation() sta.title = "起点" sta.tag = 0 sta.coordinate = staIt.coordinate() mapView.addAnnotation(sta) let end = StaEndPointAnnotation() end.title = "终点" end.tag = 1 end.coordinate = endIt.coordinate() mapView.addAnnotation(end) if !points.isEmpty { mapView.addAnnotations(points) mapView.showAnnotations(points, animated: true) } } else { print("驾车检索失败") } }
A、基础版驾车线路规划绘制线
extension RoutePlanResultViewController: BMKRouteSearchDelegate { /** 返回驾车路线检索结果 @param searcher 检索对象 @param result 检索结果,类型为BMKDrivingRouteResult @param error 错误码 @see BMKSearchErrorCode */ func onGetDrivingRouteResult(_ searcher: BMKRouteSearch!, result: BMKDrivingRouteResult!, errorCode error: BMKSearchErrorCode) { if error == BMK_SEARCH_NO_ERROR { //成功获取结果 let plan = result.routes.first var point = [BMKMapPoint]() var index = [NSNumber]() for item in plan?.steps ?? [] { if let a = item as? BMKDrivingStep { for j in 0 ..< a.pointsCount { var p = BMKMapPoint() p.x = a.points[Int(j)].x; p.y = a.points[Int(j)].y; point.append(p) DLog("111--->>>>p.x = ", p.x, "p.y = ", p.y) } if a.hasTrafficsInfo { DLog("----存在路况") for val in a.traffics { index.append(val) DLog("----加载路况===",val) } } else { DLog("----不存在路况") for _ in 0 ..< a.pointsCount { index.append(NSNumber(value: 1)) } } } } DLog("--->>>>point.count = ",point.count) if let polyline = BMKMultiPolyline(points: &point, count: UInt(point.count), drawIndexs: index) { mapView.add(polyline) mapViewFitPolyline(polyline) } } else { //检索失败 } } func mapViewFitPolyline(_ polyline: BMKPolyline) { var leftTop_x: Double, leftTop_y: Double, rightBottom_x: Double, rightBottom_y: Double if polyline.pointCount < 1 { return } let pt = polyline.points[0] leftTop_x = pt.x leftTop_y = pt.y // 左上方的点leftTop坐标(leftTop_x,leftTop_y) rightBottom_x = pt.x rightBottom_y = pt.y // 右底部的点rightBottom坐标(rightBottom_x,rightBottom_y) for i in 1..<polyline.pointCount { let point = polyline.points[Int(i)] if point.x < leftTop_x { leftTop_x = point.x } if point.x > rightBottom_x { rightBottom_x = point.x } if point.y < leftTop_y { leftTop_y = point.y } if point.y > rightBottom_y { rightBottom_y = point.y } } let rect = BMKMapRect(origin: BMKMapPoint(x: leftTop_x, y: leftTop_y), size: BMKMapSize(width: rightBottom_x - leftTop_x, height: rightBottom_y - leftTop_y)) let padding = UIEdgeInsets(top: 10, left: 10, bottom: k_safearea_bottom + 100, right: 10) mapView.fitVisibleMapRect(rect, edgePadding: padding, withAnimated: true) } }
共用地图线路渲染
extension RoutePlanResultViewController: BMKMapViewDelegate { //MARK:BMKMapViewDelegate /** 根据overlay生成对应的BMKOverlayView */ func mapView(_ mapView: BMKMapView, viewFor overlay: BMKOverlay) -> BMKOverlayView? { if overlay.isKind(of: BMKMultiPolyline.self) { let mulTexturePolylineView = BMKMultiTexturePolylineView(multiPolyline: overlay as! BMKMultiPolyline) mulTexturePolylineView?.lineWidth = 8.0 // 构建纹理数组 let images: [UIImage] = [UIImage(named: "icon_road_blue")!, UIImage(named: "icon_road_green")!, UIImage(named: "icon_road_yellow")!, UIImage(named: "icon_road_red")!] mulTexturePolylineView?.textureImages = images // LineJoinType,默认是kBMKLineJoinBevel(不支持虚线) // 拐角处圆角衔接 mulTexturePolylineView?.lineJoinType = kBMKLineJoinRound // // 拐角处平角衔接 // mulTexturePolylineView?.lineJoinType = kBMKLineJoinBevel; // // 拐角处尖角衔接,ps尖角连接(尖角过长(大于线宽)按平角处理) // mulTexturePolylineView?.lineJoinType = kBMKLineJoinMiter; return mulTexturePolylineView } if let over = overlay as? BMKPolyline { //初始化一个overlay并返回相应的BMKPolylineView的实例 let polylineView = BMKPolylineView(polyline: over) //设置polylineView的画笔颜色为蓝色 polylineView?.strokeColor = UIColor(red: 19 / 255.0, green: 107/255.0, blue: 251/255.0, alpha: 1.0) //设置polylineView的画笔宽度为16 polylineView?.lineWidth = 5 //圆点虚线,V5.0.0新增 //polylineView?.lineDashType = kBMKLineDashTypeDot //方块虚线,V5.0.0新增 //polylineView?.lineDashType = kBMKLineDashTypeSquare return polylineView } return nil } //MARK:BMKMapViewDelegate /** 根据anntation生成对应的annotationView @param mapView 地图View @param annotation 指定的标注 @return 生成的标注View */ func mapView(_ mapView: BMKMapView, viewFor annotation: BMKAnnotation) -> BMKAnnotationView? { if annotation is VmPointAnnotation { /** 根据指定标识查找一个可被复用的标注,用此方法来代替新创建一个标注,返回可被复用的标注 */ var annotationView: BMKPinAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: annotationViewIdentifier1) as? BMKPinAnnotationView if annotationView == nil { /** 初始化并返回一个annotationView @param annotation 关联的annotation对象 @param reuseIdentifier 如果要重用view,传入一个字符串,否则设为nil,建议重用view @return 初始化成功则返回annotationView,否则返回nil */ annotationView = BMKPinAnnotationView.init(annotation: annotation, reuseIdentifier: annotationViewIdentifier1) } return annotationView } if let an = annotation as? StaEndPointAnnotation { /** 根据指定标识查找一个可被复用的标注,用此方法来代替新创建一个标注,返回可被复用的标注 */ var annotationView: BMKPinAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: annotationViewIdentifier2) as? BMKPinAnnotationView if annotationView == nil { /** 初始化并返回一个annotationView @param annotation 关联的annotation对象 @param reuseIdentifier 如果要重用view,传入一个字符串,否则设为nil,建议重用view @return 初始化成功则返回annotationView,否则返回nil */ annotationView = BMKPinAnnotationView.init(annotation: annotation, reuseIdentifier: annotationViewIdentifier2) } if an.tag == 0 { annotationView?.image = UIImage(named: "icon_start") } else { annotationView?.image = UIImage(named: "icon_end") } return annotationView } return nil } }
B、导航版驾车线路规划请求
func drivingSearchV2() { guard let staIt = startItem else { return } guard let endIt = endItem else { return } var naviNodes = [BNRoutePlanNode]() let starNode = BNRoutePlanNode() let position = BNPosition() position.x = staIt.longitude?.doubleValue ?? 0 position.y = staIt.latitude?.doubleValue ?? 0 starNode.pos = position starNode.pos.eType = BNCoordinate_BaiduMapSDK naviNodes.append(starNode) for item in list { let node = BNRoutePlanNode() let pos = BNPosition() pos.x = item.longitude.doubleValue pos.y = item.latitude.doubleValue node.pos = pos node.pos.eType = BNCoordinate_BaiduMapSDK naviNodes.append(node) } let endNode = BNRoutePlanNode() let endPosition = BNPosition() endPosition.x = endIt.longitude?.doubleValue ?? 0 endPosition.y = endIt.latitude?.doubleValue ?? 0 endNode.pos = endPosition endNode.pos.eType = BNCoordinate_BaiduMapSDK naviNodes.append(endNode) let routeManager = BNaviService.getInstance()?.routePlanManager() routeManager?.startNaviRoutePlan(BNRoutePlanMode_Recommend, naviNodes: naviNodes, time: nil, delegete: self, userInfo:[BNaviTripTypeKey:BN_NaviTypeReal.rawValue]) }
B、基础版驾车线路规划绘制线
extension RoutePlanningResultViewController: BNNaviRoutePlanDelegate { /** * 算路成功回调 * @param userInfo 用户信息 */ func routePlanDidFinished(_ userInfo: [AnyHashable : Any]!) { if let route = BNaviService.getInstance().driveRouteManager().getCurrentCarRouteData() { let plan = route.carRoutes.firstObject as? BNCarOneRouteModel var point = [CLLocationCoordinate2D]() var index = [NSNumber]() for item in plan?.stepList ?? [] { if let a = item as? BNCarRouteStepModel { for l in a.coordinates { // 国测局坐标类型的原始坐标 let gcj02Coord = CLLocationCoordinate2DMake(l.y, l.x) // 转为百度经纬度类型的坐标 let bd09Coord = BMKCoordTrans(gcj02Coord, BMK_COORD_TYPE.COORDTYPE_COMMON, BMK_COORD_TYPE.COORDTYPE_BD09LL) point.append(bd09Coord) } } } // 带纹理线 if let polyline = BMKMultiPolyline(coordinates: &point, count: UInt(point.count),drawIndexs: index) { mapView.add(polyline) mapViewFitPolyline(polyline) } // 不带纹理 // if let polyline = BMKPolyline.init(coordinates: &point, count: UInt(point.count)) { // mapView.add(polyline) // mapViewFitPolyline(polyline) // } } var points = [VmPointAnnotation]() for (k,item) in list.enumerated() { let coord = CLLocationCoordinate2D(latitude:item.latitude.doubleValue, longitude: item.longitude.doubleValue) if !CLLocationCoordinate2DIsValid(coord) || coord.longitude == 0 || coord.latitude == 0 { continue } //初始化标注类BMKPointAnnotation的实例 let annotation = VmPointAnnotation.init() //设置标注的经纬度坐标 annotation.coordinate = coord //设置标注的标题 annotation.title = item.vmCode //副标题 annotation.subtitle = String(k + 1) + ":" + item.nodeName annotation.vm = item points.append(annotation) } if !points.isEmpty { mapView.addAnnotations(points) mapView.showAnnotations(points, animated: true) }
// 开启导航 // BNaviService.getInstance().uiManager().showPage(BNaviUI_NormalNavi, delegate: self, extParams:[BNaviUI_NormalNavi_TypeKey:BN_NaviTypeReal.rawValue]) } func routePlanDidFailedWithError(_ error: Error!, andUserInfo userInfo: [AnyHashable : Any]! = [:]) { } func routePlanDidUserCanceled(_ userInfo: [AnyHashable : Any]!) { } }