腾讯地图SDK公交路线规划

前言

  • 最近在研究腾讯地图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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容