Objective-C的百度地图多途径点路径规划学习笔记

545 阅读13分钟

最近学习了百度地图的多途径点路径(驾车路线规划),按照百度地图的Demo学习,实现了页面,唯一遇到的小问题就是在标注路线方向时,图标的旋转角度需要设置一下,否则全部都指向上面,代码如下:

//  UIImage+Rotate.h
//  UIImage的扩展类,用来设置图像的角度
#import <UIKit/UIKit.h>
@interface UIImage (Rotate)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees;
@end
//  UIImage+Rotate.m
#import "UIImage+Rotate.h"
@implementation UIImage (Rotate)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees
{
    
    CGFloat width = CGImageGetWidth(self.CGImage);
    CGFloat height = CGImageGetHeight(self.CGImage);
    CGSize rotatedSize;
    
    rotatedSize.width = width;
    rotatedSize.height = height;
    
    UIGraphicsBeginImageContext(rotatedSize);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
    CGContextRotateCTM(bitmap, degrees * M_PI / 180);
    CGContextRotateCTM(bitmap, M_PI);
    CGContextScaleCTM(bitmap, -1.0, 1.0);
    CGContextDrawImage(bitmap, CGRectMake(-rotatedSize.width/2, -rotatedSize.height/2, rotatedSize.width, rotatedSize.height), self.CGImage);
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
@end

//  RouteAnnotation.h
//  自定义的annotation,继承自BMKPointAnnotation

#ifndef RouteAnnotation_h
#define RouteAnnotation_h

#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface RouteAnnotation : BMKPointAnnotation

///<0:起点 1:终点 2:公交 3:地铁 4:驾乘 5:途经点  6:楼梯、电梯
@property (nonatomic) NSInteger type;
@property (nonatomic) NSInteger degree;

//根据该RouteAnnotation中Type属性的值返回对应的BMKAnnotationView
- (BMKAnnotationView*)getRouteAnnotationView:(BMKMapView *)mapview;
@end
#endif /* RouteAnnotation_h */

//  RouteAnnotation.m

#import "RouteAnnotation.h"
#import "UIImage+Rotate.h"

@implementation RouteAnnotation

@synthesize type = _type;
@synthesize degree = _degree;


- (BMKAnnotationView*)getRouteAnnotationView:(BMKMapView *)mapview
{
    BMKAnnotationView* view = nil;
    switch (_type) {
        case 0:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:@"start_node"];
                //设置centerOffset改变view的位置
                view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
                //在百度资源包中取出图像
                NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
                NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_start"];
                //view显示的图像
                view.image = [UIImage imageWithContentsOfFile:file];
            }
        }
            break;
        case 1:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"end_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"end_node"];
                //设置centerOffset改变view的位置
                view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
                //在百度资源包中取出图像
                NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
                NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_end"];
                //view显示的图像
                view.image = [UIImage imageWithContentsOfFile:file];
            }
        }
            break;
        case 2:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"bus_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"bus_node"];
                //在百度资源包中取出图像
                NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
                NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_bus"];
                //view显示的图像
                view.image = [UIImage imageWithContentsOfFile:file];
            }
        }
            break;
        case 3:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"rail_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"rail_node"];
                //在百度资源包中取出图像
                NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
                NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_rail"];
                //view显示的图像
                view.image = [UIImage imageWithContentsOfFile:file];
            }
        }
            break;
        case 4:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"route_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"route_node"];
            } else {
                [view setNeedsDisplay];
            }
            //在百度资源包中取出图像
            NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
            NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_direction"];
            //view显示的图像
            UIImage *image = [UIImage imageWithContentsOfFile:file];
            //设置图片角度
            view.image = [image imageRotatedByDegrees:_degree];
        }
            break;
        case 5:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"waypoint_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"waypoint_node"];
            } else {
                [view setNeedsDisplay];
            }
            //在百度资源包中取出图像
            NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
            NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_waypoint"];
            //view显示的图像
            UIImage *image = [UIImage imageWithContentsOfFile:file];
            //设置图片角度
            view.image = [image imageRotatedByDegrees:_degree];
        }
            break;
            
        case 6:
        {
            /**
             *根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
             *@param identifier 指定标识
             *@return 返回可被复用的标注View
             */
            view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"stairs_node"];
            if (view == nil) {
                //标注view
                view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"stairs_node"];
            }
            //在百度资源包中取出图像
            NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
            NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/stairsIcon"];
            //view显示的图像
            view.image = [UIImage imageWithContentsOfFile:file];
        }
            break;
        default:
            break;
    }
    if (view) {
        view.annotation = self;
        view.canShowCallout = YES;
    }
    return view;
}

@end

//  YSHPendPlanningTaskModel.h
//  模型

#import <Common/Common.h>

@protocol YSHPendPlanningTaskDataModel;

@interface YSHPendPlanningTaskDataModel : JSONModel
@property (nonatomic, copy) NSString *longitude;
@property (nonatomic, copy) NSString *latitude;
@property (nonatomic, assign) NSInteger is_send;
@property (nonatomic, assign) NSInteger is_have_start;
@property (nonatomic, copy) NSString *task_id;
@end

@interface YSHPendPlanningTaskModel : JSONModel
@property (nonatomic, assign) NSInteger code;
@property (nonatomic, copy) NSString *message;
@property (nonatomic, strong) NSArray <YSHPendPlanningTaskDataModel> *data;
@end
//  YSHPendPlanningTaskModel.m

#import "YSHPendPlanningTaskModel.h"

@implementation YSHPendPlanningTaskDataModel

+(BOOL)propertyIsOptional:(NSString *)propertyName{
    return YES;
}

@end

@implementation YSHPendPlanningTaskModel

+(BOOL)propertyIsOptional:(NSString *)propertyName{
    return YES;
}

@end

//  YSHRoutePlanController.h
#import <UIKit/UIKit.h>

@interface YSHRoutePlanController : UIViewController

@end
//  YSHRoutePlanController.m

#import "YSHRoutePlanController.h"
#import "YSHPendPlanningTaskModel.h"
#import <BaiduMapAPI_Map/BMKMapComponent.h>
#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>
#import <BaiduMapAPI_Search/BMKSearchComponent.h>
#import <BMKLocationKit/BMKLocationManager.h>
#import "RouteAnnotation.h"
#import "UIImage+Rotate.h"

//起点
static NSInteger const annotationStart = 0;
//终点
static NSInteger const annotationEnd = 1;
//驾车
static NSInteger const annotationDrive = 4;
//途径点
static NSInteger const annotationAfter = 5;

@interface YSHRoutePlanController ()<BMKMapViewDelegate,BMKRouteSearchDelegate,BMKLocationManagerDelegate>

@property (nonatomic, strong) YSHPendPlanningTaskModel *model;
@property (nonatomic, strong) NSMutableArray<YSHPendPlanningTaskDataModel *> *dataSource;
@property (nonatomic, copy) NSString *tripMethod;
@property (nonatomic, strong) BMKMapView *mapView;
@property (nonatomic, strong)  BMKRouteSearch * routesearch;
@property (nonatomic, strong) BMKLocationManager *locService;
@property (nonatomic, strong) BMKRouteSearch *drivingRouteSearch;
@property (nonatomic, assign) CLLocationCoordinate2D startCoor;
@end

@implementation YSHRoutePlanController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationItem.title = @"路线规划";
    [self createMapView];
}

///请求数据
-(void)loadData{
    
    self.tripMethod = [[NSUserDefaults standardUserDefaults]objectForKey:@"1001"];
    NSInteger routeRule = 2;
    if([self.tripMethod isEqualToString:@"骑行"]){
        routeRule = 2;
    }else if([self.tripMethod isEqualToString:@"驾车"]){
        routeRule = 1;
    }
    YSURequest *request = [[YSURequest alloc]initWithUrl:[NSString stringWithFormat:@"%@%@",API_PEND_PLANNING_TASK,[YSHUtils getAccount]] andWhat:0];
    [request setValue:@(routeRule) forKey:@"route_rule"];
    [self addRequest:request];
}

///请求成功
-(void)onRequestSucceed:(NSDictionary *)response ofWhat:(NSInteger)what{
    YSHPendPlanningTaskModel *model = [[YSHPendPlanningTaskModel alloc]initWithDictionary:response error:nil];
    self.model = model;
    [self.model.data enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel *dataModel,NSUInteger index,BOOL *stop){
        [self.dataSource addObject:dataModel];
    }];
    
    [self setupDefaultData];
}

///请求失败
-(void)onRequestFailed:(YSURequestError *)error ofWhat:(NSInteger)what{
    [self.view makeToast:@"网络请求异常"];
}

///创建地图
- (void)createMapView {
    self.mapView = [[BMKMapView alloc] initWithFrame:CGRectZero];
    [self.mapView setZoomLevel:12];// 地图比例尺级别
    self.mapView.showMapScaleBar = YES;// 设定是否显式比例尺
    self.mapView.delegate = self;
    [self.view addSubview:_mapView];
    [_mapView mas_makeConstraints:^(MASConstraintMaker *make){
        make.edges.equalTo(self.view);
    }];
    
    [self initLocationService];
}

///初始化定位服务
-(void)initLocationService{
    
    if (_locService==nil) {
        _locService = [[BMKLocationManager alloc]init];
    }
    _locService.delegate = self;
    //开始连续定位
    [_locService startUpdatingLocation];
    //设定是否显示定位图层
    _mapView.showsUserLocation = YES;
    //设定定位模式,默认BMKUserTrackingMode
    _mapView.userTrackingMode = BMKUserTrackingModeNone;
    //设定定位坐标系类型,默认为 BMKLocationCoordinateTypeGCJ02
    _locService.coordinateType = BMKLocationCoordinateTypeBMK09LL;
}

- (void)viewWillAppear:(BOOL)animated {
    //当mapView即将被显示的时候调用,恢复之前存储的mapView状态
    [_mapView viewWillAppear];
    _mapView.delegate = self;
}

- (void)viewWillDisappear:(BOOL)animated {
    //当mapView即将被隐藏的时候调用,存储当前mapView的状态
    [_mapView viewWillDisappear];
}

///设置驾车路线规划数据
- (void)setupDefaultData {
    
    //实例化驾车查询基础信息类
    BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc] init];
    //实例化线路检索节点信息类对象
    BMKPlanNode *start = [[BMKPlanNode alloc]init];
    //定位位置作为起点坐标
    start.pt = self.startCoor;
    
    //途径点坐标数组
    NSMutableArray <BMKPlanNode *> *wayPointsArray = [[NSMutableArray alloc]init];
    [self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        //数据源中最后一个元素分为作为终点,不加入途径点数组
        if(idx != self.dataSource.count - 1){
            CLLocationCoordinate2D coor;
            coor.latitude = [obj.latitude doubleValue];
            coor.longitude = [obj.longitude doubleValue];
            BMKPlanNode *after = [[BMKPlanNode alloc]init];
            after.pt = coor;
            [wayPointsArray addObject:after];
        }

    }];
    drivingRoutePlanOption.wayPointsArray = wayPointsArray;
    
    //在dataSource中取出终点坐标
    CLLocationCoordinate2D endCoor;
    YSHPendPlanningTaskDataModel *endLocation = [self.dataSource lastObject];
    endCoor.latitude = [endLocation.latitude doubleValue];
    endCoor.longitude = [endLocation.longitude doubleValue];
    
    //实例化线路检索节点信息类对象
    BMKPlanNode *end = [[BMKPlanNode alloc]init];
    //终点坐标
    end.pt = endCoor;
    //检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.from = start;
    //检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.to = end;
    
    [self searchData:drivingRoutePlanOption];
}

///发送驾车路线检索
- (void)searchData:(BMKDrivingRoutePlanOption *)option {
    //初始化BMKRouteSearch实例
    _drivingRouteSearch = [[BMKRouteSearch alloc]init];
    //设置驾车路径的规划
    _drivingRouteSearch.delegate = self;
    /*
     线路检索节点信息类,一个路线检索节点可以通过经纬度坐标或城市名加地名确定
     */
    //实例化线路检索节点信息类对象
    BMKPlanNode *start = [[BMKPlanNode alloc]init];
    //起点名称
    start.name = option.from.name;
    //起点坐标
    start.pt = option.from.pt;
    //起点所在城市,注:cityName和cityID同时指定时,优先使用cityID
    start.cityName = option.from.cityName;
    //起点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
    if ((option.from.cityName.length > 0 && option.from.cityID != 0) || (option.from.cityName.length == 0 && option.from.cityID != 0))  {
        start.cityID = option.from.cityID;
    }
    //实例化线路检索节点信息类对象
    BMKPlanNode *end = [[BMKPlanNode alloc]init];
    //终点名称
    end.name = option.to.name;
    //终点所在城市,注:cityName和cityID同时指定时,优先使用cityID
    end.cityName = option.to.cityName;
    //终点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
    if ((option.to.cityName.length > 0 && option.to.cityID != 0) || (option.to.cityName.length == 0 && option.to.cityID != 0))  {
        end.cityID = option.to.cityID;
    }
    //终点坐标
    end.pt = option.to.pt;
    //初始化请求参数类BMKDrivingRoutePlanOption的实例
    BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc]init];
    //检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.from = start;
    //检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.to = end;
    //检索的途径点
    drivingRoutePlanOption.wayPointsArray = option.wayPointsArray;
    /*
     驾车策略,默认使用BMK_DRIVING_TIME_FIRST
     BMK_DRIVING_BLK_FIRST:躲避拥堵
     BMK_DRIVING_TIME_FIRST:最短时间
     BMK_DRIVING_DIS_FIRST:最短路程
     BMK_DRIVING_FEE_FIRST:少走高速
     */
    drivingRoutePlanOption.drivingPolicy = option.drivingPolicy;
    /*
     路线中每一个step的路况,默认使用BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE
     BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE:不带路况
     BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE:道路和路况
     */
    drivingRoutePlanOption.drivingRequestTrafficType = option.drivingRequestTrafficType;
    /**
     发起驾乘路线检索请求,异步函数,返回结果在BMKRouteSearchDelegate的onGetDrivingRouteResult中
     */
    BOOL flag = [_drivingRouteSearch drivingSearch:drivingRoutePlanOption];
    if(flag) {
        NSLog(@"驾车检索成功");
    } else {
        NSLog(@"驾车检索失败");
    }
}

#pragma mark - BMKRouteSearchDelegate
/**
 返回驾车路线检索结果
 
 @param searcher 检索对象
 @param result 检索结果,类型为BMKDrivingRouteResult
 @param error 错误码 @see BMKSearchErrorCode
 */
- (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error {
    [_mapView removeOverlays:_mapView.overlays];
    [_mapView removeAnnotations:_mapView.annotations];
    
    if (error == BMK_SEARCH_NO_ERROR) {
        //+polylineWithPoints: count:坐标点的个数
        __block NSUInteger pointCount = 0;
        //获取所有驾车路线中第一条路线
        BMKDrivingRouteLine *routeline = (BMKDrivingRouteLine *)result.routes.firstObject;
        //遍历驾车路线中的所有路段
        [routeline.steps enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //获取驾车路线中的每条路段
            BMKDrivingStep *step = routeline.steps[idx];
            //初始化标注类RouteAnnotation的实例,RouteAnnotation继承自BMKPointAnnotation
            RouteAnnotation *annotation = [[RouteAnnotation alloc] init];
            //设置标注的经纬度坐标为子路段的入口经纬度
            annotation.coordinate = step.entrace.location;
            //设置标注的标题为子路段的说明
            annotation.title = step.entraceInstruction;
            //设置标注的角度
            annotation.degree = step.direction * 30;
            //设置标注的类型
            annotation.type = annotationDrive;
            /**
             当前地图添加标注,需要实现BMKMapViewDelegate的-mapView:viewForAnnotation:方法
             来生成标注对应的View
             @param annotation 要添加的标注
             */
            [_mapView addAnnotation:annotation];
            //统计路段所经过的地理坐标集合内点的个数
            pointCount += step.pointsCount;
        }];
        
        //添加起点annotation
        RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
        //设置标注的坐标
        annotation.coordinate = self.startCoor;
        //设置标注的类型
        annotation.type = annotationStart;
        //添加标注到地图
        [_mapView addAnnotation:annotation];
        
        [self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //创建终点的标注
           if(idx == self.dataSource.count - 1){
                CLLocationCoordinate2D coor;
                coor.latitude = [obj.latitude doubleValue];
                coor.longitude = [obj.longitude doubleValue];
                RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
                //设置标注的坐标
                annotation.coordinate = coor;
                //设置标注的类型
                annotation.type = annotationEnd;
                //添加标注到地图
                [_mapView addAnnotation:annotation];
            }
            //创建途径点标注
           else{
                CLLocationCoordinate2D coor;
                coor.latitude = [obj.latitude doubleValue];
                coor.longitude = [obj.longitude doubleValue];
                RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
                //设置标注的坐标
                annotation.coordinate = coor;
                //设置标注的类型
                annotation.type = annotationAfter;
                //添加标注到地图
                [_mapView addAnnotation:annotation];
            }
        }];
        
        //+polylineWithPoints: count:指定的直角坐标点数组
        BMKMapPoint *points = new BMKMapPoint[pointCount];
        __block NSUInteger j = 0;
        //遍历驾车路线中的所有路段
        [routeline.steps enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //获取驾车路线中的每条路段
            BMKDrivingStep *step = routeline.steps[idx];
            //遍历每条路段所经过的地理坐标集合点
            for (NSUInteger i = 0; i < step.pointsCount; i ++) {
                //将每条路段所经过的地理坐标点赋值给points
                points[j].x = step.points[i].x;
                points[j].y = step.points[i].y;
                j ++;
            }
        }];
        
        //根据指定直角坐标点生成一段折线
        BMKPolyline *polyline = [BMKPolyline polylineWithPoints:points count:pointCount];
        /**
         向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay:方法
         来生成标注对应的View
         
         @param overlay 要添加的overlay
         */
        [_mapView addOverlay:polyline];
        //根据polyline设置地图范围
        [self mapViewFitPolyline:polyline withMapView:self.mapView];
    }
}

#pragma mark - BMKMapViewDelegate
/**
 根据anntation生成对应的annotationView
 
 @param mapView 地图View
 @param annotation 指定的标注
 @return 生成的标注View
 */
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
    
    RouteAnnotation *routeAnnotation = (RouteAnnotation *)annotation;
    
    if([routeAnnotation isKindOfClass:[BMKPointAnnotation class]]){
        
        return [routeAnnotation getRouteAnnotationView:_mapView];
    }
    
    return nil;
}

/**
 根据overlay生成对应的BMKOverlayView
 
 @param mapView 地图View
 @param overlay 指定的overlay
 @return 生成的覆盖物View
 */
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
    
    if ([overlay isKindOfClass:[BMKPolyline class]]) {
        //初始化一个overlay并返回相应的BMKPolylineView的实例
        BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];
        //设置polylineView的填充色
        polylineView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:1];
        //设置polylineView的画笔(边框)颜色
        polylineView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        //设置polygonView的线宽度
        polylineView.lineWidth = 2.0;
        return polylineView;
    }
    return nil;
}

///根据polyline设置地图范围
- (void)mapViewFitPolyline:(BMKPolyline *)polyline withMapView:(BMKMapView *)mapView {
    double leftTop_x, leftTop_y, rightBottom_x, rightBottom_y;
    if (polyline.pointCount < 1) {
        return;
    }
    BMKMapPoint 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 (int i = 1; i < polyline.pointCount; i++) {
        BMKMapPoint point = polyline.points[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;
        }
    }
    BMKMapRect rect;
    rect.origin = BMKMapPointMake(leftTop_x , leftTop_y);
    rect.size = BMKMapSizeMake(rightBottom_x - leftTop_x, rightBottom_y - leftTop_y);
    UIEdgeInsets padding = UIEdgeInsetsMake(20, 10, 20, 10);
    [mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
}

#pragma make -- BMKLocationManagerDelegate
/**
 *  @brief 连续定位回调函数。
 *  @param manager 定位 BMKLocationManager 类。
 *  @param location 定位结果,参考BMKLocation。
 *  @param error 错误信息。
 */
- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
    //停止连续定位
    [_locService stopUpdatingLocation];
    //当前地图的中心点,改变该值时,地图的比例尺级别不会发生变化
    _mapView.centerCoordinate = location.location.coordinate;
    //记录起点位置坐标
    self.startCoor = location.location.coordinate;
    //发送数据请求
    [self loadData];
}

-(NSMutableArray<YSHPendPlanningTaskDataModel *> *)dataSource{
    if(_dataSource == nil){
        _dataSource = [[NSMutableArray alloc]init];
    }
    return _dataSource;
}
@end

效果如图:

WechatIMG285.jpeg

后来样式需要调整,途径点用标签表示,可以弹出气泡,气泡样式要自定义的,大概这样:

Untitled.gif 屏幕快照 2019-08-06 上午9.20.34.png

//  YSHRoutePlanPaoPaoView.h
//自定义的paopaoView

#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface YSHRoutePlanPaoPaoView : BMKActionPaopaoView

@end
//  YSHRoutePlanPaoPaoView.m

#import "YSHRoutePlanPaoPaoView.h"

@implementation YSHRoutePlanPaoPaoView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self drawView];
    }
    return self;
}

- (void)drawView{
    
    UIView *OwnPaoPaoView = [[UIView alloc]initWithFrame:self.frame];
    UILabel *detailsLabel = [[UILabel alloc]initWithFrame:OwnPaoPaoView.frame];
    detailsLabel.text = @"查看详情";
    detailsLabel.textColor = [UIColor whiteColor];
    detailsLabel.font = [YSHUiUtils fontSeven];
    detailsLabel.textAlignment = NSTextAlignmentCenter;
    detailsLabel.backgroundColor = HEXCOLOR(0x58bff);
    [OwnPaoPaoView addSubview:detailsLabel];
    [self addSubview:OwnPaoPaoView];
    
}

@end
//  YSHRoutePlanController.m

#import "YSHRoutePlanController.h"
#import "YSHPendPlanningTaskModel.h"
#import <BaiduMapAPI_Map/BMKMapComponent.h>
#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>
#import <BaiduMapAPI_Search/BMKSearchComponent.h>
#import <BMKLocationKit/BMKLocationManager.h>
#import "RouteAnnotation.h"
#import "UIImage+Rotate.h"
#import "YSHRoutePlanPaoPaoView.h"


//起点
static NSInteger const annotationStart = 0;
//终点
static NSInteger const annotationEnd = 1;
//驾车
static NSInteger const annotationDrive = 4;
//途径点
static NSInteger const annotationAfter = 5;
//发货
static NSInteger const send = 1;
//收货
static NSInteger const collect = 2;

@interface YSHRoutePlanController ()<BMKMapViewDelegate,BMKRouteSearchDelegate,BMKLocationManagerDelegate>

@property (nonatomic, strong) YSHPendPlanningTaskModel *model;
@property (nonatomic, strong) NSMutableArray<YSHPendPlanningTaskDataModel *> *dataSource;
@property (nonatomic, copy) NSString *tripMethod;
@property (nonatomic, strong) BMKMapView *mapView;
@property (nonatomic, strong) BMKRouteSearch * routesearch;
@property (nonatomic, strong) BMKLocationManager *locService;
@property (nonatomic, strong) BMKRouteSearch *drivingRouteSearch;
//记录起点坐标
@property (nonatomic, assign) CLLocationCoordinate2D startCoor;
//点击BMKAnnotationView标注时记录上一次点击的对象
@property (nonatomic, strong) BMKAnnotationView *annotationView;
@end

@implementation YSHRoutePlanController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationItem.title = @"路线规划";
    [self createMapView];
}

///请求数据
-(void)loadData{
    
    self.tripMethod = [[NSUserDefaults standardUserDefaults]objectForKey:@"1001"];
    NSInteger routeRule = 2;
    if([self.tripMethod isEqualToString:@"骑行"]){
        routeRule = 2;
    }else if([self.tripMethod isEqualToString:@"驾车"]){
        routeRule = 1;
    }
    YSURequest *request = [[YSURequest alloc]initWithUrl:[NSString stringWithFormat:@"%@%@",API_PEND_PLANNING_TASK,[YSHUtils getAccount]] andWhat:0];
    [request setValue:@(routeRule) forKey:@"route_rule"];
    [self addRequest:request];
}

///请求成功
-(void)onRequestSucceed:(NSDictionary *)response ofWhat:(NSInteger)what{
    YSHPendPlanningTaskModel *model = [[YSHPendPlanningTaskModel alloc]initWithDictionary:response error:nil];
    self.model = model;
    [self.model.data enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel *dataModel,NSUInteger index,BOOL *stop){
        [self.dataSource addObject:dataModel];
    }];
    
    [self setupDefaultData];
}

///请求失败
-(void)onRequestFailed:(YSURequestError *)error ofWhat:(NSInteger)what{
    [self.view makeToast:@"网络请求异常"];
}

///创建地图
- (void)createMapView {
    self.mapView = [[BMKMapView alloc] initWithFrame:CGRectZero];
    [self.mapView setZoomLevel:12];// 地图比例尺级别
    self.mapView.showMapScaleBar = YES;// 设定是否显式比例尺
    self.mapView.delegate = self;
    [self.view addSubview:_mapView];
    [_mapView mas_makeConstraints:^(MASConstraintMaker *make){
        make.edges.equalTo(self.view);
    }];
    
    [self initLocationService];
}

///初始化定位服务
-(void)initLocationService{
    
    if (_locService==nil) {
        _locService = [[BMKLocationManager alloc]init];
    }
    _locService.delegate = self;
    //开始连续定位
    [_locService startUpdatingLocation];
    //设定是否显示定位图层
    _mapView.showsUserLocation = YES;
    //设定定位模式,默认BMKUserTrackingMode
    _mapView.userTrackingMode = BMKUserTrackingModeNone;
    //设定定位坐标系类型,默认为 BMKLocationCoordinateTypeGCJ02
    _locService.coordinateType = BMKLocationCoordinateTypeBMK09LL;
}

- (void)viewWillAppear:(BOOL)animated {
    //当mapView即将被显示的时候调用,恢复之前存储的mapView状态
    [_mapView viewWillAppear];
    _mapView.delegate = self;
}

- (void)viewWillDisappear:(BOOL)animated {
    //当mapView即将被隐藏的时候调用,存储当前mapView的状态
    [_mapView viewWillDisappear];
}

///设置驾车路线规划数据
- (void)setupDefaultData {
    
    //实例化驾车查询基础信息类
    BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc] init];
    //实例化线路检索节点信息类对象
    BMKPlanNode *start = [[BMKPlanNode alloc]init];
    //定位位置作为起点坐标
    start.pt = self.startCoor;
    
    //途径点坐标数组
    NSMutableArray <BMKPlanNode *> *wayPointsArray = [[NSMutableArray alloc]init];
    [self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        //数据源中最后一个元素分为作为终点,不加入途径点数组
        if(idx != self.dataSource.count - 1){
            CLLocationCoordinate2D coor;
            coor.latitude = [obj.latitude doubleValue];
            coor.longitude = [obj.longitude doubleValue];
            BMKPlanNode *after = [[BMKPlanNode alloc]init];
            after.pt = coor;
            [wayPointsArray addObject:after];
        }

    }];
    drivingRoutePlanOption.wayPointsArray = wayPointsArray;
    
    //在dataSource中取出终点坐标
    CLLocationCoordinate2D endCoor;
    YSHPendPlanningTaskDataModel *endLocation = [self.dataSource lastObject];
    endCoor.latitude = [endLocation.latitude doubleValue];
    endCoor.longitude = [endLocation.longitude doubleValue];
    
    //实例化线路检索节点信息类对象
    BMKPlanNode *end = [[BMKPlanNode alloc]init];
    //终点坐标
    end.pt = endCoor;
    //检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.from = start;
    //检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.to = end;
    
    [self searchData:drivingRoutePlanOption];
}

///发送驾车路线检索
- (void)searchData:(BMKDrivingRoutePlanOption *)option {
    //初始化BMKRouteSearch实例
    _drivingRouteSearch = [[BMKRouteSearch alloc]init];
    //设置驾车路径的规划
    _drivingRouteSearch.delegate = self;
    /*
     线路检索节点信息类,一个路线检索节点可以通过经纬度坐标或城市名加地名确定
     */
    //实例化线路检索节点信息类对象
    BMKPlanNode *start = [[BMKPlanNode alloc]init];
    //起点名称
    start.name = option.from.name;
    //起点坐标
    start.pt = option.from.pt;
    //起点所在城市,注:cityName和cityID同时指定时,优先使用cityID
    start.cityName = option.from.cityName;
    //起点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
    if ((option.from.cityName.length > 0 && option.from.cityID != 0) || (option.from.cityName.length == 0 && option.from.cityID != 0))  {
        start.cityID = option.from.cityID;
    }
    //实例化线路检索节点信息类对象
    BMKPlanNode *end = [[BMKPlanNode alloc]init];
    //终点名称
    end.name = option.to.name;
    //终点所在城市,注:cityName和cityID同时指定时,优先使用cityID
    end.cityName = option.to.cityName;
    //终点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
    if ((option.to.cityName.length > 0 && option.to.cityID != 0) || (option.to.cityName.length == 0 && option.to.cityID != 0))  {
        end.cityID = option.to.cityID;
    }
    //终点坐标
    end.pt = option.to.pt;
    //初始化请求参数类BMKDrivingRoutePlanOption的实例
    BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc]init];
    //检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.from = start;
    //检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
    drivingRoutePlanOption.to = end;
    //检索的途径点
    drivingRoutePlanOption.wayPointsArray = option.wayPointsArray;
    /*
     驾车策略,默认使用BMK_DRIVING_TIME_FIRST
     BMK_DRIVING_BLK_FIRST:躲避拥堵
     BMK_DRIVING_TIME_FIRST:最短时间
     BMK_DRIVING_DIS_FIRST:最短路程
     BMK_DRIVING_FEE_FIRST:少走高速
     */
    drivingRoutePlanOption.drivingPolicy = option.drivingPolicy;
    /*
     路线中每一个step的路况,默认使用BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE
     BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE:不带路况
     BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE:道路和路况
     */
    drivingRoutePlanOption.drivingRequestTrafficType = option.drivingRequestTrafficType;
    /**
     发起驾乘路线检索请求,异步函数,返回结果在BMKRouteSearchDelegate的onGetDrivingRouteResult中
     */
    BOOL flag = [_drivingRouteSearch drivingSearch:drivingRoutePlanOption];
    if(flag) {
        NSLog(@"驾车检索成功");
    } else {
        NSLog(@"驾车检索失败");
    }
}

#pragma mark - BMKRouteSearchDelegate
/**
 返回驾车路线检索结果
 
 @param searcher 检索对象
 @param result 检索结果,类型为BMKDrivingRouteResult
 @param error 错误码 @see BMKSearchErrorCode
 */
- (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error {
    [_mapView removeOverlays:_mapView.overlays];
    [_mapView removeAnnotations:_mapView.annotations];
    
    if (error == BMK_SEARCH_NO_ERROR) {
        //+polylineWithPoints: count:坐标点的个数
        __block NSUInteger pointCount = 0;
        //获取所有驾车路线中第一条路线
        BMKDrivingRouteLine *routeline = (BMKDrivingRouteLine *)result.routes.firstObject;
        //遍历驾车路线中的所有路段
        [routeline.steps enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //获取驾车路线中的每条路段
            BMKDrivingStep *step = routeline.steps[idx];
            //初始化标注类RouteAnnotation的实例,RouteAnnotation继承自BMKPointAnnotation
            RouteAnnotation *annotation = [[RouteAnnotation alloc] init];
            //设置标注的经纬度坐标为子路段的入口经纬度
            annotation.coordinate = step.entrace.location;
            //设置标注的标题为子路段的说明
            annotation.title = step.entraceInstruction;
            //设置标注的角度
            annotation.degree = step.direction * 30;
            //设置标注的类型
            annotation.type = annotationDrive;
            /**
             当前地图添加标注,需要实现BMKMapViewDelegate的-mapView:viewForAnnotation:方法
             来生成标注对应的View
             @param annotation 要添加的标注
             */
            [_mapView addAnnotation:annotation];
            //统计路段所经过的地理坐标集合内点的个数
            pointCount += step.pointsCount;
        }];
        
        //添加起点annotation
        RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
        //设置标注的坐标
        annotation.coordinate = self.startCoor;
        //设置标注的类型
        annotation.type = annotationStart;
        //添加标注到地图
        [_mapView addAnnotation:annotation];
        
        [self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //创建终点的标注
           if(idx == self.dataSource.count - 1){
                CLLocationCoordinate2D coor;
                coor.latitude = [obj.latitude doubleValue];
                coor.longitude = [obj.longitude doubleValue];
                RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
                //设置标注的坐标
                annotation.coordinate = coor;
                //设置标注的类型
                annotation.type = annotationEnd;
                //添加标注到地图
                [_mapView addAnnotation:annotation];
            }
            //创建途径点标注
           else{
                CLLocationCoordinate2D coor;
                coor.latitude = [obj.latitude doubleValue];
                coor.longitude = [obj.longitude doubleValue];
                RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
                //设置标注的坐标
                annotation.coordinate = coor;
                //设置标注的类型
                annotation.type = annotationAfter;
                annotation.title = @"查看详情";
                annotation.is_send = obj.is_send;
                annotation.is_have_start = obj.is_have_start;
                annotation.task_id = obj.task_id;
                annotation.index = idx;
                //添加标注到地图
                [_mapView addAnnotation:annotation];
            }
        }];
        
        //+polylineWithPoints: count:指定的直角坐标点数组
        BMKMapPoint *points = new BMKMapPoint[pointCount];
        __block NSUInteger j = 0;
        //遍历驾车路线中的所有路段
        [routeline.steps enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            //获取驾车路线中的每条路段
            BMKDrivingStep *step = routeline.steps[idx];
            //遍历每条路段所经过的地理坐标集合点
            for (NSUInteger i = 0; i < step.pointsCount; i ++) {
                //将每条路段所经过的地理坐标点赋值给points
                points[j].x = step.points[i].x;
                points[j].y = step.points[i].y;
                j ++;
            }
        }];
        
        //根据指定直角坐标点生成一段折线
        BMKPolyline *polyline = [BMKPolyline polylineWithPoints:points count:pointCount];
        /**
         向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay:方法
         来生成标注对应的View
         
         @param overlay 要添加的overlay
         */
        [_mapView addOverlay:polyline];
        //根据polyline设置地图范围
        [self mapViewFitPolyline:polyline withMapView:self.mapView];
    }
}

#pragma mark - BMKMapViewDelegate
/**
 根据anntation生成对应的annotationView
 
 @param mapView 地图View
 @param annotation 指定的标注
 @return 生成的标注View
 */
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
    
    RouteAnnotation *routeAnnotation = (RouteAnnotation *)annotation;
    
    if([routeAnnotation isKindOfClass:[BMKPointAnnotation class]]){
        if(routeAnnotation.type == annotationAfter){
            BMKAnnotationView *annotationView = [routeAnnotation getRouteAnnotationView:_mapView];
            //view显示的图像
            annotationView.image = [self pathPointImage:routeAnnotation];
            //view被选中时会弹出气泡
            annotationView.canShowCallout = YES;
            //view在地图上拖动
            annotationView.draggable = YES;
            //设置显示级别,数值越大越优先展示
            annotationView.displayPriority = BMKFeatureDisplayPriorityDefaultHigh;
            return annotationView;
        }
        return [routeAnnotation getRouteAnnotationView:_mapView];
    }
    return nil;
}

/**
 根据overlay生成对应的BMKOverlayView
 
 @param mapView 地图View
 @param overlay 指定的overlay
 @return 生成的覆盖物View
 */
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
    
    if ([overlay isKindOfClass:[BMKPolyline class]]) {
        //初始化一个overlay并返回相应的BMKPolylineView的实例
        BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];
        //设置polylineView的填充色
        polylineView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:1];
        //设置polylineView的画笔(边框)颜色
        polylineView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        //设置polygonView的线宽度
        polylineView.lineWidth = 2.0;
        return polylineView;
    }
    return nil;
}

/**
 *当选中一个annotation views时,调用此接口
 *当BMKAnnotation的title为nil,BMKAnnotationView的canShowCallout为NO时,不显示气泡,点击BMKAnnotationView会回调此接口。
 *当气泡已经弹出,点击BMKAnnotationView不会继续回调此接口。
 *@param mapView 地图View
 *@param view 选中的annotation views
 */
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view {
    
    if(self.annotationView){
        [self.annotationView.paopaoView removeFromSuperview];
        [self.annotationView setSelected:NO];
        self.annotationView = nil;
    }
    //设置自定义的泡泡
    YSHRoutePlanPaoPaoView *paopao = [[YSHRoutePlanPaoPaoView alloc]initWithFrame:CGRectMake(0, -5, 50, 25)];
    //initWithCustomView需要传入继承自BMKActionPaopaoView的View,否则会返回null
    view.paopaoView = [[BMKActionPaopaoView alloc] initWithCustomView:paopao];
    self.annotationView = view;
    [mapView mapForceRefresh];
    
}

/**
 *当点击annotation view弹出的泡泡时,调用此接口
 *@param mapView 地图View
 *@param view 泡泡所属的annotation view
 */
- (void)mapView:(BMKMapView *)mapView annotationViewForBubble:(BMKAnnotationView *)view{
    NSLog(@"点击了泡泡");
}

///根据polyline设置地图范围
- (void)mapViewFitPolyline:(BMKPolyline *)polyline withMapView:(BMKMapView *)mapView {
    double leftTop_x, leftTop_y, rightBottom_x, rightBottom_y;
    if (polyline.pointCount < 1) {
        return;
    }
    BMKMapPoint 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 (int i = 1; i < polyline.pointCount; i++) {
        BMKMapPoint point = polyline.points[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;
        }
    }
    BMKMapRect rect;
    rect.origin = BMKMapPointMake(leftTop_x , leftTop_y);
    rect.size = BMKMapSizeMake(rightBottom_x - leftTop_x, rightBottom_y - leftTop_y);
    UIEdgeInsets padding = UIEdgeInsetsMake(20, 10, 20, 10);
    [mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
}

#pragma make -- BMKLocationManagerDelegate
/**
 *  @brief 连续定位回调函数。
 *  @param manager 定位 BMKLocationManager 类。
 *  @param location 定位结果,参考BMKLocation。
 *  @param error 错误信息。
 */
- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
    //停止连续定位
    [_locService stopUpdatingLocation];
    //当前地图的中心点,改变该值时,地图的比例尺级别不会发生变化
    _mapView.centerCoordinate = location.location.coordinate;
    //记录起点位置坐标
    self.startCoor = location.location.coordinate;
    //发送数据请求
    [self loadData];
}

///返回途径点坐标的图像
- (UIImage *)pathPointImage:(RouteAnnotation *)annotation{
    
    NSString *labelContent = nil;
    UILabel *label = [UILabel new];
    
    if(annotation.is_send == send){
        labelContent = [NSString stringWithFormat:@"%ld(发)",annotation.index + 1];
        label.backgroundColor = HEXCOLOR(0x10c8a8);
    }else if(annotation.is_send == collect){
        labelContent = [NSString stringWithFormat:@"%ld(收)",annotation.index + 1];
        label.backgroundColor = HEXCOLOR(0x58bff);
    }
    CGFloat labelWidth = 6*labelContent.length +6;
    label.frame = CGRectMake(0, 0, labelWidth*3, 16*3);
    label.text = labelContent;
    label.textAlignment = NSTextAlignmentCenter;
    label.textColor = [UIColor whiteColor];
    label.font = [UIFont systemFontOfSize:10*3];
    label.clipsToBounds = YES;
    
    UIGraphicsBeginImageContext(label.bounds.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [label.layer renderInContext:ctx];
    UIImage* tImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return tImage;
}

-(NSMutableArray<YSHPendPlanningTaskDataModel *> *)dataSource{
    if(_dataSource == nil){
        _dataSource = [[NSMutableArray alloc]init];
    }
    return _dataSource;
}

@end