美文网首页
腾讯地图SDK公交路线规划

腾讯地图SDK公交路线规划

作者: 面糊 | 来源:发表于2020-12-10 02:44 被阅读0次

    前言

    • 最近在研究腾讯地图SDK的检索功能,使用公交路线规划功能实现了这个小Demo,暂时还没有做同一路线不同公交线路切换功能(以后有时间可能会完善这个Demo)。

    使用场景:

    1. 公交路线规划

    准备:

    1. 腾讯地图iOS SDK

    公交路线规划检索结果的数据说明

    1. 检索结果:QMSBusingRouteSearchResult中的NSArray *routes属性包含了检索到的结果,每个结果都是一个独立的公交出行方案QMSBusingRoutePlan。

    2. 公交出行方案:QMSBusingRoutePlan,表示从起点到终点的完整出行规划

      属性 说明
      CGFloat distance 方案的总距离
      CGFloat duration 方案的预估时间
      NSString *bounds 方案的东北、西南坐标
      用于调整地图视角显示路线
      NSArray <QMSBusingSegmentRoutePlan *> *steps 总路线的分段信息(包含步行、公交,其中公交可能包含多个方案)
    3. 出行方案的分段路线规划

      属性 说明
      NSString *mode "WALKING":步行
      "TRANSIT":公交
      标记该分段的出行方式
      CGFloat distance 分段的距离
      CGFloat duration 分段的预估时间
      CGFloat price 如果是公交或者地铁,需要花费的金额,元
      NSString *direction 方向描述,如果为步行,表达为向哪个方向走
      NSArray *polyline 分段途径坐标点(这里必须说一下,腾讯地图SDK使用的是CLLocationCoordinate2D的encode类型,因此还需要decode才能使用)
      NSArray *lines 如果是公交,并且有多个线路可以乘坐的话,该数组就会包含多个路线:QMSBusingRouteTransitLine
    4. 公交线路规划:QMSBusingRouteTransitLine,到这里才是最麻烦的地方,因为是一个线路的不同方案

      属性 说明
      NSString *vehicle 交通工具:公交、地铁
      NSString *id_ 应该是个标记,没发现作用
      CGFloat distance 距离
      NSTimeInterval duration 预计乘坐时间
      NSString *title 车名:如333路、软件园通勤车等
      NSArray *polyline 途径坐标点
      NSInteger station_count 途径站的数目
      NSArray<QMSBusStation *> *stations 途径站的站名
      QMSStationEntrance *destination 目的地的地址,也就是属于哪个街道
      QMSBusStation *geton 上车车站
      QMSBusStation *getoff 下车车站

    公交路线规划的详细说明

    1. 公交路线规划的起点和终点坐标的检索(第一个麻烦的地方,不支持地名检索)

      1. 腾讯SDK的检索参数并不支持地名检索,只有坐标检索,因此要使用检索功能就必须先通过POI检索功能来获取起点和终点的坐标位置:

        - (IBAction)searchButtonClicked:(UIButton *)sender {
            _startPoiData = nil;
            _endPoiData = nil;
            
            // 起点:腾讯北京总部
            _startPoiOption = [[QMSPoiSearchOption alloc] init];
            _startPoiOption.keyword = _startPointTextField.text;
            [_startPoiOption setBoundaryByRegionWithCityName:@"北京" autoExtend:NO];
            [self.mapSearcher searchWithPoiSearchOption:_startPoiOption];
            
            // 终点:西二旗地忒站
            _endPoiOption = [[QMSPoiSearchOption alloc] init];
            _endPoiOption.keyword = _endPointTextField.text;
            [_endPoiOption setBoundaryByRegionWithCityName:@"北京" autoExtend:NO];
            [self.mapSearcher searchWithPoiSearchOption:_endPoiOption];
        }
        
        - (void)searchWithPoiSearchOption:(QMSPoiSearchOption *)poiSearchOption didReceiveResult:(QMSPoiSearchResult *)poiSearchResult {
            if (poiSearchOption == _startPoiOption) {
                _startPoiData = poiSearchResult.dataArray.firstObject;
            } else {
                _endPoiData = poiSearchResult.dataArray.firstObject;
            }
            
            
            // 添加起点终点前,先消除之前的大头针
            [self.mapView removeAnnotations:self.mapView.annotations];
            
            // 设置起点和终点
            QPointAnnotation *startPointAnnotation = [[QPointAnnotation alloc] init];
            startPointAnnotation.coordinate = _startPoiData.location;
            [self.mapView addAnnotation:startPointAnnotation];
            
            QPointAnnotation *endPointAnnotation = [[QPointAnnotation alloc] init];
            endPointAnnotation.coordinate = _endPoiData.location;
            [self.mapView addAnnotation:endPointAnnotation];
            
            // 发起公交路线规划检索
            [self searchBusRoute];
        }
        
      2. 通过起点和终点POI数据来发起公交路线规划检索

        - (void)searchBusRoute {
            if (_startPoiData != nil && _endPoiData != nil) {
                QMSBusingRouteSearchOption *option = [[QMSBusingRouteSearchOption alloc] init];
                [option setFromCoordinate:_startPoiData.location];
                [option setToCoordinate:_endPoiData.location];
                
                [self.mapSearcher searchWithBusingRouteSearchOption:option];
            }
        }
        
        image.png
    2. 显示所有路线的基本信息

      1. 获取方案的数量:planCount

        NSInteger planCount = busingRouteSearchResult.routes.count;
        
      2. 创建路线方案模型数组,在这里我在保存了路线的同事,提出了几样数据:

        // 路线方案
        @property (nonatomic, strong) QMSBusingRoutePlan *routePlan;
        // 路线预估时间
        @property (nonatomic, assign) NSInteger duration;
        // 路线的步行距离
        @property (nonatomic, assign) CGFloat distance;
        // 途径的公交车站数
        @property (nonatomic, assign) NSInteger stationCount;
        // 上车站名称
        @property (nonatomic, strong) NSString *startStationName;
        
      3. 获取路线的步行距离:需要遍历方案中的所有分段信息,判断是否为步行,然后累加distance:

        // 遍历方案中的步骤
        for (int i = 0; i < plan.steps.count; i++) {
            QMSBusingSegmentRoutePlan *segmentRoutePlan = plan.steps[i];
            
            // 判断步骤为步行,累计距离
            if ([self routeIsWalkingPlan:segmentRoutePlan]) {
                walkingDistance += segmentRoutePlan.distance;
            }
        }
        
      4. 获取途径的公交站总数和上车站名称:由于同一分段可能有多个公交出行方案,在此只演示了默认第一条方案:

        // 判断步骤为公交
        if ([self routeIsTransitPlan:segmentRoutePlan]) {
            // 遍历经过的公交
            for (int j = 0; j < segmentRoutePlan.lines.count; j++) {
                QMSBusingRouteTransitLine *line = segmentRoutePlan.lines[j];
                // 公交站数
                stationCount += line.station_count;
                
                // 第一站名称
                if (j == 0) {
                    QMSBusStation *station = line.stations.firstObject;
                    startStationName = station.title;
                }
            }
        }
        
      5. 通过TableView来展示所有的方案:

        image.png
    3. 选择方案,展示路线图

      1. 先获取该方案总共的分段数:

        NSInteger stepCount = routePlan.steps.count;
        
      2. 通过判断分段方案的类型,来区分虚线和蚯蚓线:

        if ([self routeIsWalkingPlan:plan]) {
            // 步行虚线
            CLLocationCoordinate2D coords[plan.polyline.count];
            for (int i = 0; i < plan.polyline.count; i++) {
                NSValue *value = plan.polyline[i];
                CLLocationCoordinate2D coord = [value coordinateValue];
                coords[i] = coord;
            }
        
            QPolyline *walkingPolyline = [[QPolyline alloc] initWithCoordinates:coords count:plan.polyline.count];
            // QPolyline中的userData属性可以用来添加自定义的内容去判断数据
            walkingPolyline.userData = @"WALKING";
            [self.mapView addOverlay:walkingPolyline];
            
        } else {
        
            // 驾车蚯蚓线
            QMSBusingRouteTransitLine *line = plan.lines[0];
            CLLocationCoordinate2D coords[line.polyline.count];
            for (int i = 0; i < line.polyline.count; i++) {
                NSValue *value = line.polyline[i];
                CLLocationCoordinate2D coord = [value coordinateValue];
                coords[i] = coord;
            }
        
            QPolyline *busPolyline = [[QPolyline alloc] initWithCoordinates:coords count:line.polyline.count];
            busPolyline.userData = @"TRANSIT";
            [self.mapView addOverlay:busPolyline];
        }
        
      3. 最后,实现代理方法去绘制线路:

        - (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay {
            if ([overlay isKindOfClass:[QPolyline class]]) {
                QPolyline *polyline = (QPolyline *)overlay;
                NSString *userData = (NSString *)polyline.userData;
                
                if ([userData isEqualToString:@"WALKING"]) {
                    // 步行虚线
                    QPolylineView *polylineView = [[QPolylineView alloc] initWithPolyline:polyline];
                    polylineView.lineWidth = 8;
                    polylineView.lineDashPattern = @[@15, @10];
                    polylineView.strokeColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
                    
                    return polylineView;
                } else {
                    // 驾车蚯蚓线
                    QTexturePolylineView *polylineView = [[QTexturePolylineView alloc] initWithPolyline:polyline];
                    polylineView.drawType = QTextureLineDrawType_ColorLine;
                    // 路线箭头
                    polylineView.drawSymbol = YES;
                    polylineView.lineWidth = 8;
                    polylineView.strokeColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.8];
                    
                    return polylineView;
                }
            }
            
            return nil;
        }
        
      4. 补充:当添加完毕之后,让地图的视野自动适配路线

        1. 路线方案中的NSString *bounds属性标记了西南、东北两个方向的坐标,但是这个两个坐标组合成了一个字符串,还需要我们自己去解析:

          - (QCoordinateBounds)boundsFromString:(NSString *)boundsString {
              NSArray *array = [boundsString componentsSeparatedByString:@","];
              NSString *southWestLatString = array[0];
              NSString *southWestLongString = array[1];
              NSString *northEastLatString = array[2];
              NSString *northEastLongString = array[3];
              CLLocationCoordinate2D northEast = CLLocationCoordinate2DMake(northEastLatString.floatValue, northEastLongString.floatValue);
              CLLocationCoordinate2D southWest = CLLocationCoordinate2DMake(southWestLatString.floatValue, southWestLongString.floatValue);
              
              QCoordinateBounds bounds;
              bounds.northEast = northEast;
              bounds.southWest = southWest;
              
              return bounds;
          }
          
        2. 最后调用地图接口,调整地图显示范围:

          [self.mapView setVisibleMapRect:QMapRectForCoordinateBounds(bounds) edgePadding:UIEdgeInsetsMake(10, 10, 10, 10) animated:YES];
          
      5. 最终显示效果:

        image.png

    吐槽

    1. 官方文档还是有很多需要补充的地方,至少这些嵌套的路线方案(对象属性)就需要理解一阵。
    2. 坐标给的并不是很直接,有decode的NSValue类型,还有NSString类型需要去切割字符串然后再转化。
    3. 同一分段路线的不同公交方案,这里的处理需要细心处理。
    4. 为什么检索不支持文字的起点终点呢?

    Demo下载

    链接: https://pan.baidu.com/s/1vHbpPW5_1E0UmAlx5GBVQg 密码: q1tt

    相关文章

      网友评论

          本文标题:腾讯地图SDK公交路线规划

          本文链接:https://www.haomeiwen.com/subject/xbflgktx.html