Skill: lbs-bmap/baidu-map-ios-sdk (version 1.0.1)

--- name: baidu-map-ios-sdk description: 百度地图 iOS SDK 与 BMKLocationKit 集成与开发规范。覆盖地图、定位、步骑行导航、检索、路线、标注与覆盖物；输出专业地图方案。可快捷使用百度地图 SDK 的能力与数据，构建功能丰富、交互性强的专业地图类应用。 compatibility: iOS, Xcode, CocoaPods --- # 百度地图 iOS SDK ## 目标与边界 - **目标**：在 iOS 工程中正确集成百度地图/定位/步骑行导航，并给出符合隐私与坐标系规范的实现方案。 - **负责**：BaiduMapKit、BMKLocationKit、BaiduWalkNaviKit 的集成、配置、API 选用与示例；与技能内 reference 文档一致。 - **不负责**：驾车导航细节（百度地图驾车导航文档）、服务端逻辑、非百度 SDK、UI 视觉设计（仅遵循 [ui-standards.md](references/ui-standards.md) 的规范）。 ## 使用时机 满足其一即启用本技能： - 关键词：百度地图、BMKMapView、BMKLocationKit、步骑行导航、BaiduWalkNaviKit、标注、路线规划、CocoaPods 集成、BD09、定位鉴权 - 需求类型：地图展示、单次/连续/后台定位、步行或骑行实时导航、POI/标注/覆盖物、路线绘制、逆地理、轨迹动画、点聚合、隐私弹窗 **按需加载**：先根据需求在 [reference.md](references/reference.md) 中选定文档，再引用对应 references 内容；需求含糊时先向用户澄清再给方案。 ## 集成与编码顺序 - **未集成百度地图 SDK 时**：先配置并执行 CocoaPods（编写/补全 Podfile → 执行 `pod install` → 使用生成的 `.xcworkspace` 打开），**在能正确导入 SDK 头文件之后**再编写调用地图/定位/检索等的代码。这样既避免使用 `#if __has_include(...)` 做条件编译，也能以实际 SDK 头文件为准写代码，减少接口不一致或编译错误。 - **本地已集成 SDK 时**：直接按需导入头文件并写代码，**以当前工程内的 SDK 版本、头文件及接口为准**；类名、方法、参数与本地头文件一致，不写不存在的 API。若编译报错提示符号不存在，提示开发者核对或更新 Pod 版本后再重试。 ## Agent 执行要求 1. **AK 与 Bundle 主动提示** 在编写或集成使用地图/定位 SDK 的代码时，**主动提示开发者**： - 在 [百度 LBS 控制台](https://lbsyun.baidu.com/) 申请 **iOS 应用 AK**，且应用的 **Bundle Identifier** 必须与工程中 `PRODUCT_BUNDLE_IDENTIFIER` 一致； - 在代码或配置中预留/替换 AK 的位置（如 `AppDelegate` 中的 key、或说明需在控制台配置），并注明「将 `YOUR_AK` 替换为实际 AK」。 - 若工程尚未配置 Bundle ID，提醒开发者设置并与控制台申请时填写的包名一致。 2. **代码写完自动执行编译修复，编译无误后停止** 完成与百度地图/定位相关的代码修改后，**必须**按以下流程执行，**不得在编译未通过时结束**： - **自动执行编译**：使用 `xcodebuild -workspace xxx.xcworkspace -scheme xxx -destination 'generic/platform=iOS' build`（或等价命令；CocoaPods 工程用 workspace，纯工程用 project）。 - **若编译报错**：根据报错信息**立即修复**（类名、方法签名、头文件、ARC、协议声明等），修复后**再次执行编译**。 - **循环**：重复「编译 → 若有错误则修复 → 再编译」，直至**编译通过、无错误**。 - **编译无误后停止**：仅当 build 成功（BUILD SUCCEEDED）后，才结束本轮代码修改与修复，不再继续做与编译无关的额外修改。 3. **配置 Launch Screen 避免 App 非全屏** 集成地图或涉及全屏展示时，**必须**确保工程已配置 Launch Screen，避免运行后出现黑边、非全屏。具体见 [project-config.md](references/project-config.md)「窗口初始化/Launch Screen」： - 工程内存在 **LaunchScreen.storyboard**（或等效 Launch 资源），并加入 target 的 Resources； - Info.plist 中配置 **UILaunchStoryboardName** 为 `LaunchScreen`； - 若缺失，主动创建或补充说明，并提醒开发者添加该配置。 ## 必须遵守的规则 1. **隐私与配置** - 首次使用前必须弹窗让用户阅读并同意隐私政策，再调用对应接口。 - **地图**：`[BMKMapManager setAgreePrivacy:YES]`（**类方法**，勿用 `sharedInstance`；未同意时检索可返回 nil）。 - **定位**：通过 **BMKLocationAuth** 的 **setAgreePrivacy** 在用户同意后再初始化 BMKLocationManager 等；详见 [location.md](references/location.md)。 - Info.plist 必配 **CFBundleDisplayName**；使用定位时配 NSLocationWhenInUseUsageDescription 等。详见 [project-config.md](references/project-config.md)。 - **AK 与 Bundle**：编写集成代码时主动提示开发者提供/配置 AK，且 Bundle Identifier 与百度控制台申请一致（见上文「Agent 执行要求」）。 - **Launch Screen**：必须配置 LaunchScreen.storyboard 与 Info.plist 的 UILaunchStoryboardName，避免运行后 App 非全屏、黑边；见 [project-config.md](references/project-config.md)。 2. **坐标系** - 地图 SDK 全局 **BD09**；定位 SDK 默认 **GCJ02**。与地图混用时须统一为 BD09：将定位 **coordinateType** 设为 **BMKLocationCoordinateTypeBMK09LL**，或使用 [utils.md](references/utils.md) 的 BMKCoordTrans 转换。 3. **标注与几何（必须遵守）** - **点标注优先使用 Marker，不得使用 Annotation/PinAnnotation**：点标注**必须优先**使用 **BMKIconMarker/BMKTextMarker**（addOverlay 体系），**禁止**使用 BMKPointAnnotation、BMKAnnotationView、BMKPinAnnotationView（addAnnotation 体系）除非以下例外：点聚合（BMKClusterManager 必须用 BMKPointAnnotation）、固定屏选点（isLockedToScreen）等仅 addAnnotation 能实现的场景。起终点、小车、普通图钉等一律用 Marker。详见 [overlays.md](references/overlays.md)、[annotations.md](references/annotations.md)。 - 距离、视野、方位等用 [utils.md](references/utils.md) 的 BMKGeometry 等，勿手写。 - **路线与起终点须优先使用纹理**：绘制**路线**时优先使用 **BMKPolylineView.textureImage**（图片宽高须为 2 的 n 次幂）或路况场景使用 **BMKMultiTexturePolylineView** + [assets](references/assets.md) 路况纹理；**起终点**的 BMKIconMarker.icon 须优先使用 [assets](references/assets.md) 的 **icon_start、icon_end**；仅当无可用纹理时再使用 strokeColor/纯色或自绘。见 [overlays.md](references/overlays.md)「路线与起终点：纹理优先」。 - **路线小车纹理**：路线上的小车图标**必须优先使用**本技能 [assets](references/assets.md)（`assets/images/`）提供的纹理图（如 icon_car、car_triangle、track_car）；仅当无可用纹理时，才使用纯色或自绘图片。 4. **步骑行：按需求区分两种方案** - **路线规划（算路+画线）**：BMKRouteSearch（BaiduMapKit），walkingSearch/ridingSearch，得到路线后自绘折线。见 [route.md](references/route.md)。 - **步骑行实时导航**：BaiduWalkNaviKit，Manager + 诱导、TTS、偏航纠偏、多实例/无UI。见 [navi.md](references/navi.md)。 - 二者是**不同服务**：仅需画线用 route；需实时导航用 navi。给出方案前先按开发者需求选对文档。 5. **版本与 API 以本地为准**（与上文「集成与编码顺序」一致） - 已集成 SDK：**以工程内 SDK 版本与头文件为准**，类名、方法、参数与头文件一致；不写 `#if __has_include`，直接导入头文件后写代码。 - 若某类、方法或属性在用户工程中**不存在**（编译报错或头文件无此符号），**提示用户将对应 Pod 更新到最新版本**后再重试，勿强行按文档写不存在的 API。 6. **Logo 不可遮挡与路线视野适配（必须考虑）** - **Logo 不能被遮挡**：百度地图 Logo 不可移除、不允许被 UI 遮挡。有浮动栏/底部栏时**必须**使用 `setMapPadding` 预留边界（如顶部预留检索面板、底部预留 barH+4），使 Logo 落在可见内容区内。详见 [ui-standards.md](references/ui-standards.md)「地图 Logo、指南针与 mapPadding」。 - **路线适配视野必须做**：有路线绘制时**必须**调用 `fitVisibleMapRect:edgePadding:withAnimated:` 做视野适配，edgePadding 按 [ui-standards.md](references/ui-standards.md)「路线视野适配」预留（顶部检索面板+50+marker、底部底部栏+20+marker、左右 50+marker 等），避免路线或起终点被裁切或被 UI 遮挡。mapPadding 与 fitVisibleMapRect 的 edgePadding 分开使用，勿混用。 ## 输出规范（可评估） 给出方案时需满足： - **可落地**：含具体类名、方法、调用顺序与必要配置（如 Info.plist、隐私调用时机、Launch Screen）。 - **可验证**：隐私与坐标系处理明确；若涉及定位鉴权失败，方案中可指向 [location.md](references/location.md) 的「鉴权失败排查」。 - **可组合**：按 [reference.md](references/reference.md) 选文档与常见组合；步骑行选型见规则 4。 - **AK/Bundle 提示**：涉及地图/定位初始化时，明确提示开发者配置 AK 与 Bundle Identifier。 - **编写后编译直至通过**：完成代码编写后，自动执行 xcodebuild 编译；若有报错则根据错误修复并重新编译，循环直至编译无误，再停止。 - **全屏与 Launch Screen**：涉及地图全屏或窗口大小时，确认或说明已配置 LaunchScreen.storyboard 与 UILaunchStoryboardName，避免运行后非全屏、黑边。 - **Logo 不遮挡**：涉及地图且有浮动栏/底部栏时，方案中**必须**包含 setMapPadding，并说明底部预留尽量小（如 barH+4），确保 Logo 不被遮挡。 - **路线视野适配**：涉及路线绘制时，方案中**必须**包含 fitVisibleMapRect 的 edgePadding 设置，按 ui-standards 预留顶底左右，确保路线与起终点在可视区内且不被 UI 遮挡。 - **点标注用 Marker**：涉及地图点标注（起终点、小车、图钉等）时，**必须**使用 BMKIconMarker/BMKTextMarker（addOverlay），不得使用 BMKPointAnnotation/BMKPinAnnotationView，除非点聚合、固定屏选点等例外场景。 - **路线与起终点纹理优先**：涉及路线折线或起终点 Marker 时，**必须**优先使用纹理（路线：BMKPolylineView.textureImage 或 BMKMultiTexturePolylineView；起终点：BMKIconMarker.icon 使用 [assets](references/assets.md) 的 icon_start/icon_end），仅无可用纹理时再写 strokeColor 或自绘；见 [overlays.md](references/overlays.md)「路线与起终点：纹理优先」。 方案结构：需求 → 对应文档 → 配置与依赖（含 AK/Bundle、Launch Screen）→ 关键 API → 示例片段 → 注意事项（含 Logo/路线视野、Marker 优先）。 ## 参考索引 - 选文档与边界：[reference.md](references/reference.md) - 类速查：[class-index.md](references/class-index.md) - 定位/鉴权：[location.md](references/location.md) - 步骑行导航：[navi.md](references/navi.md) - 资源：[assets.md](references/assets.md)

path: _meta.json
content: ownerId: kn72hkpg708gjrfmw7934hatex82qkkj
slug: baidu-map-ios-sdk
version: 1.0.0
publishedAt: 1773220509770

path: references/assets.md
content: # 图片资源

**边界**：技能内 `assets/images/` 图片及用途；集成与构建见 [cocoapods.md](cocoapods.md)、[project-config.md](project-config.md)。

**路线小车**：路线上的小车图标**必须优先使用**本技能提供的纹理图（下表 icon_car / car_triangle / track_car）；仅当无可用纹理时，才使用纯色或自绘图片。实现时先 `[UIImage imageNamed:@"icon_car"]`（或对应名称），为 nil 再回退。

| 图片 | 用途 |
|------|------|
| icon_car | 小车 marker（**路线小车优先**） |
| car_triangle | 带方向小车（车头朝上） |
| track_car | 带方向小车（车头朝右），**轨迹动画推荐** |
| icon_start | 起点标注 |
| icon_end | 终点标注 |
| icon_via | 途经点 |
| **路况纹理**（BMKMultiPolyline + BMKMultiTexturePolylineView，drawIndexs 来自 BMKDrivingStep.traffics） | |
| traffic_texture_unknown | 无数据（traffics=0，drawIndex 0） |
| traffic_texture_smooth | 畅通（traffics=1，drawIndex 1） |
| traffic_texture_slow | 缓行（traffics=2，drawIndex 2） |
| traffic_texture_congestion | 拥堵（traffics=3，drawIndex 3） |
| traffic_texture_severe_congestion | 严重拥堵（traffics=4，drawIndex 4） |


path: references/navi.md
content: # 导航

**边界**：应用内步骑行实时导航（BaiduWalkNaviKit），与 BMKRouteSearch 算路画线为不同能力；多路线选路、诱导、TTS、偏航纠偏均属本能力。算路与画线见 [route.md](route.md)。

---

## 步骑行实时导航（BaiduWalkNaviKit）经验与注意事项

### 基本原则

1. **每次切换导航算路前必须销毁**：在发起新一轮算路（如再次点击「步行/骑行导航」或切换起终点）前，必须调用 **`[BMKWalkNavigationManager destroy]`** 与 **`[BMKCycleNavigationManager destroy]`**，再创建新 container 并 `initNaviEngine`、`routePlanWithParams`。否则上一次的引擎状态会干扰本次算路或导航，易出现无路线、回调错乱等问题。
2. **Manager 与类型一致**：步行只用 `BMKWalkNavigationManager sharedManager`，骑行只用 `BMKCycleNavigationManager sharedManager`；LaunchParam 的 `naviType`（如 `BMK_WALK_CYCLE_NAVIGATION_TYPE_NORMAL_CYCLE`）与回调里的 `naviType` 判断一致，避免混用。
3. **不在算路/导航进行中销毁**：仅在**新一轮算路开始前**调用 destroy；仅释放业务侧对「传给 initNaviEngine 的 container」的引用，且应在**启动导航之后**再置 nil（见下）。
4. **多路线流程**：`enableMultiRoute = YES` 且设置 `routePlanDelegate`、`calcRouteDelegate` → `routePlanWithParams` → 多路线结果在 `onRoutePlanResult:naviType:` → 用 `getWalkNaviMulRouteInfos`/`getCycleNaviMulRouteInfos` 与 `displayRoutePlanResult:mapView` 在地图展示 → 用户选路线后调用 `naviCalcRoute:(routeIndex)` → 引擎算路完成后 `onNaviCalcRouteResult:naviType:` → 再 `startWalkNaviWithParentController`/`startCycleNaviWithParentController`。

### 导航生命周期与 container

- 传给 `initNaviEngine:` 的 **container（UIViewController）** 会被引擎用于地图/导航视图；若在回调里**过早**置 nil，引擎依赖的 controller 可能被释放，导致**进入导航无路线**。
- **正确做法**：在 `onNaviCalcRouteResult` 中，**仅在算路失败时**置 nil container；**算路成功时**先调用 `startWalkNavi`/`startCycleNavi`，**在启动导航之后再**置 nil container（步行可紧接着置 nil；骑行建议在 `dispatch_async(main_queue)` 的 block 内先 `startCycleNavi` 再置 nil，并可保留 block 内对 container 的强引用以免提前释放）。

示例（骑行，选路后进入导航）：

```objc
- (void)onNaviCalcRouteResult:(BMKWalkCycleRoutePlanErrorCode)errorCode naviType:(BMKWalkCycleNavigationType)naviType {
    if (errorCode != BMK_WALK_CYCLE_ROUTEPLAN_RESULT_SUCCESS) {
        _walkCycleNaviContainer = nil;
        // 提示错误...
        return;
    }
    if (naviType == BMK_WALK_CYCLE_NAVIGATION_TYPE_WALK) {
        [[BMKWalkNavigationManager sharedManager] startWalkNaviWithParentController:self isPush:YES];
        _walkCycleNaviContainer = nil;
    } else if (naviType == BMK_WALK_CYCLE_NAVIGATION_TYPE_NORMAL_CYCLE || naviType == BMK_WALK_CYCLE_NAVIGATION_TYPE_ELECTRIC_CYCLE) {
        __weak typeof(self) wself = self;
        UIViewController *container = _walkCycleNaviContainer;
        dispatch_async(dispatch_get_main_queue(), ^{
            if (wself) [[BMKCycleNavigationManager sharedManager] startCycleNaviWithParentController:wself isPush:YES];
            wself.walkCycleNaviContainer = nil;
            (void)container;
        });
    }
}
```

### 骑行多路线与展示

- 骑行也支持多路线：`enableMultiRoute = YES`、`routePlanDelegate = self`，与步行一致；选路后对骑行调用 `[[BMKCycleNavigationManager sharedManager] naviCalcRoute:(NSInteger)index]`。
- 骑行引擎建议用 `initNaviEngine:options:` 传入 `BMKWalkCycleNavigationOptions`（含 `displayOption`），并设置 `cycleNaviMode = BMK_CYCLE_NAVIGATION_MODE_NORMAL`；container 的 view 在 init 前可设 `frame = [UIScreen mainScreen].bounds` 以便路线正确布局。

### 驾车与步骑行分工

- **驾车**：可用 [utils.md](utils.md) 的 **BMKNavigation** `openBaiduMapNavigation:` 调起百度地图客户端。
- **步骑行**：应用内导航用 BaiduWalkNaviKit 的 Walk/Cycle Manager，算路前需先拿到用户位置（如 BMKLocationManager 单次定位），再组 LaunchParam（startNode/endNode，type `BMKWalkNavigationRouteNodeLocation`）调用 `routePlanWithParams:`。

---

## 按需方案（导航相关）

| 需求 | 能力组合 | 说明 |
|------|----------|------|
| 驾车调起导航 | BMKNavigation openBaiduMapNavigation: | 调起百度地图客户端，见 utils.md |
| 步骑行多路线选路+应用内导航 | BaiduWalkNaviKit enableMultiRoute + routePlanDelegate + displayRoutePlanResult + naviCalcRoute | 多路线在地图展示折线，用户选路线后 naviCalcRoute(index)，onNaviCalcRouteResult 后再 start 导航；container 在启动导航后再置 nil |
| 多实例后台投屏 | BMKBackgroundMapView + getBackgroundNavigationView | 步骑行导航画面投到外接屏/小窗：mapview、roadNetView、navigationView（由 Manager.getBackgroundNavigationView 获取），startRender/stopRender。详见 [mapview.md](mapview.md)「BMKBackgroundMapView」 |


path: references/mapview.md
content: # BMKMapView 地图视图

**边界**：地图视图、属性、生命周期、控制（BMKMapView）；标注见 [annotations.md](annotations.md)，覆盖物见 [overlays.md](overlays.md)。

## 概述

`BMKMapView` 继承 `UIView`，用于显示地图并执行相关操作。需配合 `BMKMapViewDelegate` 使用。

### 示例：创建地图与生命周期

```objc
#import <BaiduMapAPI_Base/BMKBaseComponent.h>
#import <BaiduMapAPI_Map/BMKMapComponent.h>

@property (nonatomic, strong) BMKMapView *mapView;

- (void)viewDidLoad {
    [super viewDidLoad];
    _mapView = [[BMKMapView alloc] initWithFrame:self.view.bounds];
    _mapView.delegate = self;
    [self.view addSubview:_mapView];
    // 可选：设置中心与缩放（改 centerCoordinate 不改变 zoomLevel）
    _mapView.centerCoordinate = CLLocationCoordinate2DMake(39.917, 116.379);
    _mapView.zoomLevel = 18;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [_mapView viewWillAppear];
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [_mapView viewWillDisappear];
}
```

### 示例：设置地图状态（带动画、指定时长）

```objc
// 使用 BMKMapStatus 设置层级与中心，带动画且指定动画时长(ms)
BMKMapStatus *status = [[BMKMapStatus alloc] init];
status.fLevel = 10;
status.targetGeoPt = CLLocationCoordinate2DMake(51.50556, -0.07556);
[_mapView setMapStatus:status withAnimation:YES withAnimationTime:1000];
```

### 示例：室内图

```objc
_mapView.baseIndoorMapEnabled = YES;
_mapView.showIndoorMapPoi = YES;
// 进入/移出室内图回调：mapView:baseIndoorMapWithIn:baseIndoorMapInfo:
```

## 地图引擎与生命周期

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKMapManager | BMKMapManager.h | 主引擎，`start:`、`setAgreePrivacy:` |
| BMKMapView | BMKMapView.h | 地图视图 |
| BMKMapStatus | BMKMapStatus.h | 地图状态（中心、缩放、旋转） |

**生命周期（必须调用）**：viewWillAppear/viewWillDisappear 必须调 mapView 对应方法，否则地图状态异常。

```objc
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [_mapView viewWillAppear];
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [_mapView viewWillDisappear];
}
```

### 地图显示当前定位

- 设置 **showsUserLocation = YES**，再通过 **updateLocationData:** 传入 **BMKUserLocation**（含 `location`、可选 `heading`），地图会绘制定位点。
- 定位数据需自行获取（如 BMKLocationManager 单次/连续定位）；与地图混用时坐标系须为 BD09（coordinateType 或转换），见 [location.md](location.md)。

```objc
_mapView.showsUserLocation = YES;
// 在拿到定位结果后（主线程）：
BMKUserLocation *userLoc = [BMKUserLocation new];
userLoc.location = [[CLLocation alloc] initWithLatitude:lat longitude:lng];
userLoc.updating = NO;
[_mapView updateLocationData:userLoc];
```

**注意**：仅在设置 showsUserLocation 且至少调用一次 updateLocationData 传入有效 CLLocation 后，地图上才会显示蓝点；未授权或定位失败时可不调用 updateLocationData。

**俯仰角**：`overlooking` 范围 -45～0，更陡需设 `minOverlooking`（-79～0）。`overlookEnabled` 是否支持俯仰角手势。

---

## 核心属性

### Delegate 与手势

| 属性 | 类型 | 说明 |
|------|------|------|
| delegate | id\<BMKMapViewDelegate\> | 地图回调 |
| gestureDelegate | id\<BMKMapGestureDelegate\> | 手势回调，返回 YES 时拦截地图处理 |

### 地图类型与语言

| 属性 | 类型 | 说明 |
|------|------|------|
| mapType | BMKMapType | 标准/卫星地图 |
| languageType | BMKMapLanguageType | 中/英文地图（since 6.4.0），V6.6.2 起英文不支持个性化地图 |
| backgroundColor | UIColor | 空白地图背景色（since 6.5.4） |
| backgroundImage | UIImage | 底图加载时背景网格（since 6.5.9，≤500KB） |

### 显示范围与中心

| 属性 | 类型 | 说明 |
|------|------|------|
| region | BMKCoordinateRegion | 当前经纬度范围 |
| limitMapRegion | BMKCoordinateRegion | 限制显示范围 |
| centerCoordinate | CLLocationCoordinate2D | 中心点（改值不改变 zoomLevel） |
| visibleMapRect | BMKMapRect | 当前可见范围（直角坐标） |

### 比例尺与视角

| 属性 | 类型 | 说明 |
|------|------|------|
| zoomLevel | float | 比例尺级别，手机 4～21 |
| minZoomLevel / maxZoomLevel | float | 自定义最小/最大级别 |
| rotation | int | 旋转角度 -180～180 |
| overlooking | int | 俯视角度 -45～0 |
| minOverlooking | int | 俯视最小值 -79～0 |
| fontSizeLevel | NSInteger | 字体大小 0～3（小/标准/大/特大，since 6.3.0） |

### 控件与 UI

| 属性 | 类型 | 说明 |
|------|------|------|
| compassPosition | CGPoint | 指南针位置（以左上角为原点） |
| compassSize | CGSize | 指南针宽高（只读） |
| showMapScaleBar | BOOL | 是否显示比例尺 |
| mapScaleBarPosition | CGPoint | 比例尺位置（以 BMKMapView 左上角为原点）；默认与 Logo 重叠，需手动设置使比例尺在 Logo 上方，见 [ui-standards.md](ui-standards.md) |
| mapScaleBarSize | CGSize | 比例尺宽高（只读） |
| mapScaleBarColor / mapScaleBarTextColor | UIColor | 比例尺颜色 |
| logoPosition | BMKLogoPosition | Logo 位置 |

### 图层与显示

| 属性 | 类型 | 说明 |
|------|------|------|
| buildingsEnabled | BOOL | 3D 楼块 |
| showMapPoi | BOOL | 底图 POI 标注 |
| trafficEnabled | BOOL | 路况图层 |
| customTrafficColorEnabled | BOOL | 自定义路况颜色生效（since 6.6.3） |
| baiduHeatMapEnabled | BOOL | 百度城市热力图（层级>11 可显示） |

### 手势

| 属性 | 类型 | 说明 |
|------|------|------|
| gesturesEnabled | BOOL | 所有手势 |
| doubleTapHoldPanEnabled | BOOL | 单指双击滑动缩放，默认 NO |
| zoomEnabled | BOOL | 双指缩放 |
| zoomEnabledWithTap | BOOL | 双击/双指单击缩放 |
| scrollEnabled | BOOL | 移动地图 |
| overlookEnabled | BOOL | 俯仰角 |
| rotateEnabled | BOOL | 旋转 |
| forceTouchEnabled | BOOL | 3D Touch 回调 |
| gestureZoomAnimationEnabled | BOOL | 手势缩放动画（since 6.5.2） |

**手势冲突（地图+ScrollView 共存）**：实现 `shouldRecognizeSimultaneouslyWithGestureRecognizer:` 返回 YES。ScrollView 配置见 [ui-standards.md](ui-standards.md)。

**BMKMapGestureDelegate**：handleTapGesture、handlePanGesture、handleFlyingGesture、handleLongGesture、handleDoubleTapGesture、handleTwoFingersTapGesture、handleTwoFingersPanGesture、handleRotationGesture、handlePinchGesture；返回 YES 时地图不处理。用于与底部抽屉、侧滑菜单等共存。

**BMKAnnotationView/BMKActionPaopaoView**：不推荐直接添加手势，会覆盖点击、长按；如必须添加，将手势 delegate 设到对应 View 并实现协调方法。

### 其他

| 属性 | 类型 | 说明 |
|------|------|------|
| mapPadding | UIEdgeInsets | 地图预留边界；设置后 Logo、比例尺、指南针会避开该区域 |
| updateTargetScreenPtWhenMapPaddingChanged | BOOL | mapPadding 改变时中心是否跟着变 |
| ChangeWithTouchPointCenterEnabled | BOOL | 双指以手势中心/地图中心旋转缩放 |
| ChangeCenterWithDoubleTouchPointEnabled | BOOL | 双击以双击位置/地图中心放大 |
| supportBackgroundDraw | BOOL | 后台绘制（since 6.6.6，进出前后台时设置） |

**mapPadding 与 fitVisibleMapRect edgePadding 区别**：mapPadding 影响指南针、Logo、比例尺位置，用于解决控件被 UI 遮挡；fitVisibleMapRect 的 edgePadding 用于路线视野适配（含 UI 边距和 marker 尺寸）。二者解决不同问题，详见 [ui-standards.md](ui-standards.md)。

---

## 类方法（创建前设置）

| 方法 | 说明 |
|------|------|
| `+ setBaiduMapSDKMetalEnable:` | 是否用 Metal 绘制（V6.5.2，创建前有效） |
| `+ getBaiduMapSDKMetalEnable` | 获取 Metal 开关（V6.6.3） |
| `+ setBaiduMapSDKOverlayNewVersionEnable:` | 覆盖物新版逻辑（V6.5.9，启动期间仅一次） |
| `+ getBaiduMapSDKOverlayNewVersionEnable` | 获取覆盖物新版开关（V6.6.3） |

---

## 实例方法

### 生命周期（必须调用）

| 方法 | 说明 |
|------|------|
| `viewWillAppear` | 即将显示时调用，恢复状态 |
| `viewWillDisappear` | 即将隐藏时调用，存储状态 |

### 地图控制

| 方法 | 说明 |
|------|------|
| `setRegion:animated:` | 设定显示范围 |
| `setCenterCoordinate:animated:` | 设定中心点 |
| `setVisibleMapRect:animated:` | 设定可见范围（直角坐标） |
| `setVisibleMapRect:edgePadding:animated:` | 设定范围并留边距 |
| `fitVisibleMapRect:edgePadding:withAnimated:` | 适配 mapRect 到可见区域 |
| `zoomIn` / `zoomOut` | 放大/缩小一级 |
| `mapForceRefresh` | 强制刷新 |
| `cleanCacheWithMapType:` | 清空缓存 |

### 坐标转换

| 方法 | 说明 |
|------|------|
| `convertCoordinate:toPointToView:` | 经纬度→View 坐标 |
| `convertPoint:toCoordinateFromView:` | View 坐标→经纬度 |
| `convertRegion:toRectToView:` | 经纬度区域→View 矩形 |
| `convertRect:toRegionFromView:` | View 矩形→经纬度区域 |
| `convertMapRect:toRectToView:` | BMKMapRect→View 矩形 |
| `convertRect:toMapRectFromView:` | View 矩形→BMKMapRect |
| `screenPointFromMapPoint3:` | 三维地理坐标→屏幕坐标（since 6.5.2） |
| `glPointForMapPoint:` | BMKMapPoint→OpenGL 坐标 |
| `glPointsForMapPoints:count:` | 批量 BMKMapPoint→OpenGL 坐标 |

### 地图状态

| 方法 | 说明 |
|------|------|
| `getMapStatus` | 获取地图状态 |
| `setMapStatus:` | 设置地图状态 |
| `setMapStatus:withAnimation:` | 设置并动画 |
| `setMapStatus:withAnimation:withAnimationTime:` | 指定动画时长(ms) |
| `getMapStatusFromCoordinateRegion:edgePadding:` | 根据区域和边距计算 BMKMapStatus |
| `setMapCenterToScreenPt:` | 设置中心点屏幕坐标 |

**设置状态并动画**：见上文「示例：设置地图状态（带动画、指定时长）」；不指定时长用 `setMapStatus:withAnimation:` 则使用 SDK 默认动画时长。

### 截图与路况

| 方法 | 说明 |
|------|------|
| `takeSnapshot` | 可视区域截图 |
| `takeSnapshot:` | 指定区域截图 |
| `setCompassImage:` | 设置罗盘图片 |
| `setCustomTrafficColorForSmooth:slow:congestion:severeCongestion:` | 自定义路况颜色（4 种全设） |
| `isSurpportBaiduHeatMap` | 当前区域是否支持百度热力图 |

### OpenGL（3D 绘制）

| 方法 | 说明 |
|------|------|
| `getProjectionMatrix` | 获取投影矩阵 |
| `getViewMatrix` | 获取视图矩阵 |

---

## Category：CustomMapAPI

| 方法 | 说明 |
|------|------|
| `setCustomMapStylePath:` | 个性化地图样式路径（创建后调用，V6.6.2 英文不支持） |
| `setCustomMapStylePath:mode:` | mode 0 本地 1 在线 |
| `setCustomMapStyleEnable:` | 个性化样式开关 |
| `setCustomMapStyleWithOption:preLoad:success:failure:` | 在线个性化样式 |

---

## Category：IndoorMapAPI

| 属性/方法 | 说明 |
|------|------|
| baseIndoorMapEnabled | 是否显示室内图 |
| showIndoorMapPoi | 室内图标注 |
| showDotPoi | 麻点 POI |
| `switchBaseIndoorMapFloor:withID:` | 切换楼层 |
| `getFocusedBaseIndoorMapInfo` | 当前聚焦室内图信息 |

---

## Category：LocationViewAPI

| 属性/方法 | 说明 |
|------|------|
| showsUserLocation | 是否显示定位图层 |
| userTrackingMode | 定位模式 |
| userLocationVisible | 定位点是否在可视区域（只读） |
| `updateLocationViewWithParam:` | 定制我的位置样式 |
| `updateLocationData:` | 更新定位数据 |

---

## Category：AnnotationAPI

| 属性/方法 | 说明 |
|------|------|
| annotations | 已添加标注数组（只读） |
| isSelectedAnnotationViewFront | 选中标注是否置顶 |
| `addAnnotation:` / `addAnnotations:` | 添加标注 |
| `removeAnnotation:` / `removeAnnotations:` | 移除标注 |
| `viewForAnnotation:` | 查找标注对应 View |
| `dequeueReusableAnnotationViewWithIdentifier:` | 复用标注 View |
| `selectAnnotation:animated:` / `deselectAnnotation:animated:` | 选中/取消选中 |
| `showAnnotations:animated:` | 显示区域包含所有标注 |
| `showAnnotations:padding:animated:` | 带边距（since 6.5.7） |
| `annotationsInCoordinateBounds:` | 矩形区域内标注 |

---

## Category：OverlaysAPI

| 属性/方法 | 说明 |
|------|------|
| overlays | 已添加 overlay 数组（只读） |
| `addOverlay:` / `addOverlays:` | 添加 overlay |
| `removeOverlay:` / `removeOverlays:` | 移除 overlay |
| `insertOverlay:atIndex:` | 指定索引插入 |
| `exchangeOverlayAtIndex:withOverlayAtIndex:` | 交换 |
| `insertOverlay:aboveOverlay:` / `belowOverlay:` | 相对插入 |
| `viewForOverlay:` | 查找 overlay 对应 View |

---

## Category：HeatMapAPI

| 方法 | 说明 |
|------|------|
| `addHeatMap:` | 添加热力图 |
| `updateHeatMap:` | 更新热力图（会重置动画） |
| `removeHeatMap` | 移除热力图 |
| `startHeatMapFrameAnimation` / `stopHeatMapFrameAnimation` | 开始/暂停动画 |
| `setHeatMapFrameAnimationIndex:` | 控制帧索引 |

---

## Category：HexagonHeatMapAPI（since 6.6.0）

| 属性/方法 | 说明 |
|------|------|
| showHexagonHeatMap | 是否显示蜂窝热力图 |
| `addHexagonHeatMap:` | 添加 |
| `removeHexagonHeatMap` | 删除 |

---

## Category：MapLayerAPI

| 属性/方法 | 说明 |
|------|------|
| showOperateLayer | 运营图层（since 6.4.0） |
| showOperatePOILayer | 运营 POI 图层（since 6.6.3） |
| showTrafficUGCLayer | 路况事件图层（since 6.6.3） |
| showDEMLayer | 地形图层（since 6.5.9） |
| `switchLayerOrder:otherLayer:` | 交换图层顺序（since 6.5.9） |
| `switchOverlayLayerAndNavigationLayer:` | overlay 与导航图层交换 |
| `switchOverlayLayerAndPOILayer:` | overlay 与 POI 图层交换（addOverlay 后调用） |
| `getPoiTagEnable:` / `setPoiTagEnable:poiTagType:` | 底图 POI 标签显示 |

---

## Category：ParticleEffect（since 6.5.7）

| 方法 | 说明 |
|------|------|
| `showParticleEffect:` | 显示粒子效果 |
| `closeParticleEffect:` | 关闭粒子效果 |
| `customParticleEffect:option:` | 自定义粒子效果 |

---

## BMKBackgroundMapView（后台投屏视图）

**BMKBackgroundMapView**（BMKBackgroundMapView.h）用于将**地图或导航画面**渲染到自定 View，可置于外接屏、投屏窗口或本机副区域，常用于**步骑行多实例后台投屏**：导航进行时把同一段导航同时投到另一块屏或小窗。

### 三层内容与对应类

BMKBackgroundMapView 支持三类内容，通过以下属性挂接：

| 属性 | 类型 | 支持的内容 | 说明 |
|------|------|-------------|------|
| **mapview** | BMKMapView | 底图 | 关联源地图，同步数据；步骑行多实例时可设为 `[multiNaviView getNaviMapView]` |
| **roadNetView** | BMKBackgroundRoadNetView | 路网、路况、路名 | 只读获取，用于自定义路网样式（见下） |
| **navigationView** | BMKBackgroundNavigationView | 导航路线、小车、罗盘、起终点等 | 步骑行由 Manager 的 `getBackgroundNavigationView` 得到并赋值（见下） |

渲染控制：设置完成后调用 **`startRender`**，退出或暂停时 **`stopRender`**，再 `removeFromSuperview`。完整步骑行投屏流程见 [navi.md](navi.md)「多实例后台投屏」。

### BMKBackgroundNavigationView 支持的内容

用于在投屏上绘制**导航相关**内容，步骑行场景下由 **BMKWalkNavigationManager** / **BMKCycleNavigationManager** 的 **`getBackgroundNavigationView`** 返回，引擎会驱动路线与位置更新，无需自行调用 `updateRouteInfo:` 等。

| 能力 | 属性/方法 | 说明 |
|------|-----------|------|
| 路线 | routeColor, routePassedColor, routePassedDisplayMode（如 Grayed） | 未走/已走路线颜色与显示模式 |
| 起终点与途径点 | needDrawStartPoint, needDrawEndPoint, needDrawViaPoint；startPointIcon, endPointIcon, viaPointIcon 等 | 是否绘制及图标 |
| 导航车标与罗盘 | navigationIcon, needDrawCompass, needFllowPhoneHeading | 车头朝向、罗盘、随手机朝向 |
| 引导线（偏航） | needDrawGuideLine, guideLineColor, guideLineWidth | 偏离路线时的引导线 |
| 路名 | needDrawRouteName, routeNameFont, routeNameTextColor 等 | 路线上的路名绘制 |
| 数据更新（非步骑行自管时） | updateRouteInfo:, updateRouteSegmentsInfo:, updateNaviLocationInfo: | 自管数据源时使用；步骑行由 Manager 提供实例则不需要 |

### BMKBackgroundRoadNetView 支持的内容

从 **`backgroundMapView.roadNetView`** 只读获取，用于在底图之上自定义**路网层**样式（不改变地图数据，仅表现）。

| 能力 | 属性 | 说明 |
|------|------|------|
| 路网 | needDrawRoadNet, roadNetColor | 是否绘制路网、路网颜色 |
| 路况 | needDrawRoadTraffic, roadTrafficColor | 是否绘制路况；需关联 mapview 的 trafficEnabled 为 YES；颜色数组 count 为 5（未知/畅通/缓行/拥挤/严重拥堵） |
| 路名 | needDrawRoadName, roadNameFont, roadNameTextColor | 是否绘制路名及字体、颜色 |

渲染由 BMKBackgroundMapView 的 startRender 统一驱动；roadNetView 的 **mapview** 需与 backgroundMapView 的 mapview 一致以同步数据。

### BMKBackgroundMapView 自身属性与接口

| 属性/方法 | 类型/说明 |
|-----------|-----------|
| **mapview** | BMKMapView，关联源地图 |
| **navigationView** | BMKBackgroundNavigationView，步骑行时设为 Manager 的 `getBackgroundNavigationView` |
| **roadNetView** | BMKBackgroundRoadNetView（只读），用于配置路网/路况/路名 |
| **frameRate** | NSInteger，渲染帧率，默认 30，范围 10～60 |
| **enable3D** | BOOL，默认 YES |
| **showScaleBar** | BOOL，是否显示比例尺 |
| **mapScreenExtOffset** | CGPoint，地图额外偏移（微调车标位置等） |
| **startRender** / **stopRender** | 开始/停止渲染 |
| **takeSnapshot:needLogo:** | 截屏 |

---

## BMKMapViewDelegate 回调

### 生命周期与渲染

| 回调 | 说明 |
|------|------|
| `mapViewWillBackground:` | 退到后台前 |
| `mapViewDidForeground:` | 进入前台后 |
| `mapViewDidFinishLoading:` | 地图初始化完毕 |
| `mapViewDidRenderValidData:withError:` | 绘制出有效数据 |
| `mapViewDidFinishRendering:` | 渲染完毕 |
| `mapView:onDrawMapFrame:` | 每帧绘制、重绘时 |

### 区域变化

| 回调 | 说明 |
|------|------|
| `mapView:regionWillChangeAnimated:` | 区域即将改变 |
| `mapView:regionWillChangeAnimated:reason:` | 带原因（Gesture/Event/APIs） |
| `mapView:regionDidChangeAnimated:` | 区域改变完成 |
| `mapView:regionDidChangeAnimated:reason:` | 带原因 |

### 标注

| 回调 | 说明 |
|------|------|
| `mapView:viewForAnnotation:` | 根据 annotation 生成 View（必须实现） |
| `mapView:didAddAnnotationViews:` | 新添加 annotation views |
| `mapView:clickAnnotationView:` | 点击 annotation view |
| `mapView:didSelectAnnotationView:` | 选中 |
| `mapView:didDeselectAnnotationView:` | 取消选中 |
| `mapView:annotationView:didChangeDragState:fromOldState:` | 拖拽状态变化 |
| `mapView:annotationViewForBubble:` | 点击气泡 |

### 覆盖物

| 回调 | 说明 |
|------|------|
| `mapView:viewForOverlay:` | 根据 overlay 生成 View（必须实现） |
| `mapView:didAddOverlayViews:` | 新添加 overlay views |
| `mapView:onClickedBMKOverlayView:` | 点击覆盖物 |

### 地图点击

| 回调 | 说明 |
|------|------|
| `mapView:onClickedMapPoi:` | 点击底图标注 |
| `mapView:onClickedMapBlank:` | 点击空白处 |
| `mapview:onDoubleClick:` | 双击 |
| `mapview:onLongClick:` | 长按 |
| `mapview:onForceTouch:force:maximumPossibleForce:` | 3D Touch |

### 其他

| 回调 | 说明 |
|------|------|
| `mapStatusDidChanged:` | 地图状态改变完成 |
| `mapview:baseIndoorMapWithIn:baseIndoorMapInfo:` | 进入/移出室内图 |
| `mapView:didChangeUserTrackingMode:` | 定位模式切换 |
| `mapViewOnClickCompass:` | 点击指南针 |

---

## 相关枚举与类型

### BMKUserTrackingMode

| 值 | 说明 |
|------|------|
| None | 普通定位 |
| Heading | 定位方向 |
| Follow | 定位跟随 |
| FollowWithHeading | 定位罗盘 |

### BMKLogoPosition

左/中/右 × 上/下 共 6 种。

### BMKRegionChangeReason

| 值 | 说明 |
|------|------|
| Gesture | 手势 |
| Event | 控件事件 |
| APIs | 接口调用 |

### BMKMapParticleEffect

雪、雨、雾霾、沙尘暴、烟花、花瓣等。

### BMKMapPoi

底图点击返回：`text`、`pt`、`uid`、`trafficUGCType`。

### BMKLayerType

kBMKLayerSDKOverlay、kBMKLayerSDKHeatMap、kBMKLayerSDKHexagonHeatMap、kBMKLayerNewSDKDefaultOverlay。


path: references/search.md
content: # 检索服务

**边界**：Sug、地理编码、逆地理、POI、公交等检索；路线算路见 [route.md](route.md)。检索类继承 BMKSearchBase，Option + Delegate 模式；使用前须 `[BMKMapManager setAgreePrivacy:YES]`（见 [SKILL.md](../SKILL.md)）。

## 规范

- 每次检索可新建实例，或复用并重设 delegate
- Option 参数按需设置，city 类参数用于过滤/提高精度
- 回调中先判断 `errorCode == BMK_SEARCH_NO_ERROR` 再处理 result

**常用错误码**（BMKSearchErrorCode）：`BMK_SEARCH_NO_ERROR` 成功；`BMK_SEARCH_AMBIGUOUS_KEYWORD` 关键字歧义；`BMK_SEARCH_NOT_SUPPORT_BUS` 不支持公交；[REDACTED_SECRET] 不支持跨城公交；`BMK_SEARCH_RESULT_NOT_FOUND` 无结果；`BMK_SEARCH_ST_EN_TOO_NEAR` 起终点过近；其他见头文件 BMKSearchBase.h。

## 地点检索（建议检索 Sug）

> 地点检索使用 BMKSuggestionSearch，参考 EmptyApp/LocationSearchViewController。

### 核心类

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKSuggestionSearch | BMKSuggestionSearch.h | 输入联想/地点检索 |
| BMKSuggestionSearchOption | BMKSuggestionSearchOption.h | 检索参数 |
| BMKSuggestionInfo | BMKSuggestionInfo.h | 单条结果 |
| BMKSuggestionSearchResult | BMKSuggestionSearchResult.h | suggestionList |

### BMKSuggestionSearchOption（参数一览）

| 属性 | 类型/说明 |
|------|-----------|
| keyword | 搜索关键字，**必选** |
| cityname | 城市名或 citycode，**必选** |
| cityLimit | BOOL：NO=全国，YES=仅该城市（海外暂不支持） |
| location | CLLocationCoordinate2D，指定位置，可选 |
| filterDistance | 过滤距离（米），与 location 配合 |
| leftBottom / rightTop | 图区范围（CLLocationCoordinate2D），与 filterDistance 二选一 |
| hotword | 是否仅透出热词 |
| inputLanguageType / languageType | 输入/输出语言类型 |
| serverType | 境内/境外（6.6.6+） |

**方法**：`suggestionSearch:`。**回调**：`onGetSuggestionResult:result:errorCode:`，result.suggestionList 为 BMKSuggestionInfo 数组。

### BMKSuggestionInfo 结果字段

| 属性 | 说明 |
|------|------|
| key | 联想词名称 |
| location | 经纬度坐标 |
| uid | 唯一标识 |
| province / city / district / town | 省/市/区/街道 |
| cityID / townCode / adcode | 编码 |
| address | 地址 |
| tag | 分类 |
| children | 子节点（BMKSuggestionChildrenInfo） |

**子节点展示**：BMKSuggestionChildrenInfo 有 `name`、`showName`、`uid`；展示时**优先用 showName（简称）**，无则用 name。示例：`NSString *displayName = (c.showName.length ? c.showName : c.name) ?: @"";`

**子 POI 选点与坐标**：用户点击子 POI（门、停车场等）时，需用**该子点的坐标**而非主 POI 坐标。做法：用**子 POI 的 uid** 直接发起 **POI 详情检索**（`BMKPoiSearch` 的 `poiDetailSearch:`），`BMKPOIDetailSearchOption.poiUIDs = @[ childUid ]`（即 **childUid**，不是主 POI 的 uid）。回调 `onGetPoiDetailResult` 中 `result.poiInfoList.firstObject` 即为该子点，取其 `pt`、`address` 用于选点回调。

### Sug 结果与无经纬度首条

**注意**：Sug 结果的第一条可能存在**没有经纬度**的情况。该条为输入联想出的**关键词/泛指名称**，不对应任何确切 POI 点。例如输入「肯」，第一条可能为「肯德基」——这是泛指，不会带 location 等字段，无法作为地图选点使用。

**实现建议**：**不要过滤**无经纬度的项，应一并展示。用户**点击**无经纬度项时，将其 **key 当作关键词填入检索框并继续发起 Sug 检索**（相当于用户补全输入后再搜），而非当作选点回调；仅当用户点击带有效经纬度的项时，再回调选点（如 onSelectPlace）。

### 推荐用法：Sug + POI 组合

- **输入过程中**：以 **Sug 检索**为入口，边输入边出联想/热词，响应快、体验好。
- **输入结束后**：若 Sug 仍未给出满意结果（列表为空或用户继续输入完整关键词），可再用 **POI 检索**（如 `BMKPOISearch` + `BMKPOICitySearchOption`，以当前关键字为 `keyword`）继续搜索，补足 POI 列表。

组合流程：用户输入 → Sug 防抖请求 → 有结果则展示（无经纬度项点击后当作关键词继续检索）；无结果或用户确认「搜不到」时，再发起 POI 城市检索。

### 地点检索 UI 实现要点

见 [ui-standards.md](ui-standards.md)（防抖、关键字长度、结果展示、检索框与列表对齐、行前 pin 图标）。**隐私检查**：检索前检查 `setAgreePrivacy`，未同意时提示并引导。**选择回调**：`onSelectLocation(BMKSuggestionInfo *)`，取消时传 nil。

**性能优化**：防抖约 0.25s；`becomeFirstResponder` 用 `dispatch_async` 延后至下一 RunLoop，避免与页面转场同时进行导致卡顿；避免在 `viewDidAppear` 中自定义 searchBar 内部结构（如 leftView），易引发布局卡顿。

```objc
// 检索
BMKSuggestionSearch *sug = [[BMKSuggestionSearch alloc] init];
sug.delegate = self;
BMKSuggestionSearchOption *opt = [[BMKSuggestionSearchOption alloc] init];
opt.keyword = keyword;
opt.cityname = @"北京市";
opt.cityLimit = YES;
[sug suggestionSearch:opt];

// 回调
- (void)onGetSuggestionResult:(BMKSuggestionSearch *)searcher result:(BMKSuggestionSearchResult *)result errorCode:(BMKSearchErrorCode)error {
    if (error != BMK_SEARCH_NO_ERROR) { /* 清空列表 */ return; }
    NSArray *list = result.suggestionList ?: @[];
    // 刷新 UITableView
}
```

## 地理编码

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKGeoCodeSearch | BMKGeoCodeSearch.h | 地理编码/逆地理编码 |
| BMKGeoCodeSearchOption | BMKGeoCodeSearchOption.h | address、city |
| BMKReverseGeoCodeSearchOption | BMKReverseGeoCodeSearchOption.h | 逆地理参数 |

**BMKGeoCodeSearchOption**：`address`（必填）、`city`（可选，多城市同名时过滤）。支持「*路与*路交叉口」描述。**方法**：`geoCode:`. **回调**：`onGetGeoCodeResult:result:errorCode:`，result 含 location、level、precise 等。

**BMKReverseGeoCodeSearchOption（逆地理参数一览）**：

| 属性 | 说明 |
|------|------|
| location | CLLocationCoordinate2D，**必填** |
| isLatestAdmin | 是否返回最新行政区划，建议 YES |
| pageNum / pageSize | POI 列表分页 |
| radius | 召回半径（米） |
| languageType | 输出语言 |
| extensionsRoad | 是否扩展道路信息 |
| entirePoi | 是否返回全量 POI |
| sortStrategy | 排序策略 |
| tags | 过滤标签 |

**逆地理（地图选点）**：设置 `location`（如 mapView.centerCoordinate）、`isLatestAdmin = YES`。**回调**：`onGetReverseGeoCodeResult:result:errorCode:`。`BMKReverseGeoCodeSearchResult` 含 `address`、`sematicDescription`、`poiList`（BMKPoiInfo）、`poiRegions`、addressComponent 等。选点场景：regionDidChange 时对中心点做逆地理，第一行展示 address，后续行展示 poiList；选中 POI 可 `setCenterCoordinate:animated:`。

## POI 检索

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKPOISearch | BMKPOISearch.h | POI 检索，delegate 接收结果 |
| BMKPOICitySearchOption | BMKPoiSearchOption.h | 城市内检索 |
| BMKPOINearbySearchOption | BMKPoiSearchOption.h | 周边检索 |
| BMKPOIBoundSearchOption | BMKPoiSearchOption.h | 矩形范围内检索 |
| BMKPOIDetailSearchOption | BMKPoiSearchOption.h | POI 详情（按 UID） |
| BMKPOIIndoorSearchOption | BMKPoiSearchOption.h | 室内 POI |

**BMKPOICitySearchOption**：keyword、city（必填）、pageIndex、pageSize、scope、tags、type、filter、filterDistance、location、leftBottom/rightTop、isCityLimit、isBoundLimit、addressResult、homonym、extensionsChildPoi、extensionsAdcode、inputLanguageType、languageType、serverType、isLightVersion、showPhotos。

**BMKPOINearbySearchOption**：keywords（数组）、location、radius、pageIndex、pageSize、scope、tags、type、filter、isRadiusLimit、addressResult、homonym、extensionsChildPoi、extensionsAdcode、inputLanguageType、languageType、serverType、isLightVersion、showPhotos。

**BMKPOIBoundSearchOption**：keywords、leftBottom、rightTop、pageIndex、pageSize、scope、tags、type、filter、addressResult、homonym、extensionsChildPoi、extensionsAdcode、inputLanguageType、languageType、serverType、isLightVersion、showPhotos。

**BMKPOIDetailSearchOption**：poiUIDs（POI 唯一标识数组，必填）、scope、languageType、extensionsAdcode、serverType、showPhotos。**子 POI**：可直接传入**子 POI 的 uid**（如 Sug 结果中 BMKSuggestionChildrenInfo.uid），接口会返回该子点的详情（pt、address 等），无需传主 POI uid 再在 detailInfo.children 中匹配。

**POI 详情/列表返回图片（photos）**：接口默认不返回图片；需同时满足：(1) **scope = BMK_POI_SCOPE_DETAIL_INFORMATION**；(2) **showPhotos = YES**。POI 图片为高级字段，AK 需在控制台申请对应权限，否则仍可能无图。城市/周边/详情检索的 Option 均有 showPhotos，仅当 scope 为详情时生效。

```objc
BMKPOIDetailSearchOption *opt = [BMKPOIDetailSearchOption new];
opt.poiUIDs = @[poiUid];
opt.scope = BMK_POI_SCOPE_DETAIL_INFORMATION;
opt.showPhotos = YES;
[self.poiSearch poiDetailSearch:opt];
```

**BMKPOIIndoorSearchOption**：indoorID、keyword、floor、pageIndex、pageSize。

**方法**：`poiSearchInCity:`、`poiSearchNearBy:`、`poiSearchInbounds:`、`poiDetailSearch:`、`poiIndoorSearch:`。**回调**：`onGetPoiResult:result:errorCode:type:`（城市/周边/矩形）、`onGetPoiDetailResult:result:errorCode:`、`onGetPoiIndoorResult:result:errorCode:`。结果中 poiInfoList / poiIndoorInfoList 为 BMKPoiInfo 数组；详情为 BMKPOIDetailSearchResult，含 BMKPOIDetailInfo（含 name、address、location、photos、openingHours、price、overallRating 等）。

## 公交

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKBusLineSearch | BMKBusLineSearch.h | 公交线路详情（按线路 UID） |

**BMKBusLineSearchOption**：线路 UID（从 POI 或路线结果获取）、city、languageType、pageIndex、pageSize 等。**方法**：按 UID 查询线路站点与走向。**回调**：`onGetBusDetailResult:result:errorCode:`。与路线规划中的「公交路线」为不同能力：此处查单条线路详情，路线规划用 BMKRouteSearch 的 transitSearch / busRoutePlanSearch。

## 其他检索

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKDistrictSearch | BMKDistrictSearch.h | 行政区域（省市区边界等） |
| BMKAOISearch | BMKAOISearch.h | AOI 检索（面状区域） |
| BMKBuildingSearch | BMKBuildingSearch.h | 建筑物检索（高级） |
| BMKGeoCodeBatchSearch / 逆地理批量 | 见 SDK 头文件 | 批量地理编码/逆地理（若有需求） |

---

## 按需方案

| 需求 | 推荐检索 | 说明 |
|------|----------|------|
| 起终点/地点选点 | BMKSuggestionSearch | keyword+city，返回 location、key、address，见 LocationSearchViewController |
| 地图拖拽选点 | BMKPointAnnotation/BMKIconMarker + BMKGeoCodeSearch | 固定屏幕标注 + 逆地理。标注见 [annotations.md](annotations.md)，regionDidChange 时 reverseGeoCode。布局见 [ui-standards.md](ui-standards.md) |
| 地址→坐标 | BMKGeoCodeSearch | address+city，结构化地址精度更高 |
| 坐标→地址 | BMKReverseGeoCodeSearch | 逆地理 |
| 城市内 POI | BMKPOISearch + BMKPOICitySearchOption | 关键字+城市 |
| 公交线路详情 | BMKBusLineSearch | 需线路 UID |


path: references/reference.md
content: # 百度地图 iOS SDK 参考索引

按需选下表文档；通用规则（隐私、坐标系、版本以本地为准）见 [SKILL.md](../SKILL.md)。

## 按需求选文档

| 你要做的 | 用到的文档 |
|----------|------------|
| 集成 Pod、选地图/定位/步骑行/导航套件 | [cocoapods.md](cocoapods.md) |
| Info.plist、隐私弹窗、Launch Screen、构建沙盒 | [project-config.md](project-config.md) |
| 单次/连续/后台/室内定位、地理围栏、鉴权失败 | [location.md](location.md) |
| 地图视图、属性、生命周期、全屏 | [mapview.md](mapview.md) |
| 点标注、固定屏、点聚合展示 | [annotations.md](annotations.md) |
| 覆盖物、热力、点聚合逻辑、轨迹、Marker/RichView | [overlays.md](overlays.md) |
| 检索/路线/选点/弹窗/视野/Logo 等 UI 规范 | [ui-standards.md](ui-standards.md) |
| Sug、地理编码、逆地理、POI、公交 | [search.md](search.md) |
| 驾车/步行/骑行/公交**算路与画线**（BMKRouteSearch，仅算路+画线） | [route.md](route.md) |
| **步骑行实时导航**（BaiduWalkNaviKit，诱导、TTS、偏航纠偏、多实例） | [navi.md](navi.md) |
| 坐标转换、几何、视野适配、调起地图 | [utils.md](utils.md) |
| 图片资源路径与命名 | [assets.md](assets.md) |
| 类与头文件速查 | [class-index.md](class-index.md) |

**步骑行**：算路画线（route）与实时导航（navi）为**不同服务**——仅画线用 route，要诱导/TTS/偏航用 [navi.md](navi.md)。

## 文档一览与边界

| 文档 | 内容 | 边界 |
|------|------|------|
| [cocoapods.md](cocoapods.md) | Podfile、pod 命令、地图/定位/步骑行套件 | 构建报错见 [project-config.md](project-config.md) |
| [project-config.md](project-config.md) | Info.plist、隐私弹窗、Launch Screen、CocoaPods 沙盒 | 仅百度 SDK 相关配置 |
| [location.md](location.md) | BMKLocationKit、定位方式、鉴权排查、坐标系 | 不含步骑行导航内部定位 |
| [mapview.md](mapview.md) | BMKMapView、状态、生命周期 | 不含标注/覆盖物具体类型 |
| [annotations.md](annotations.md) | 标注、固定屏、点聚合展示 | 聚类逻辑见 [overlays.md](overlays.md) |
| [overlays.md](overlays.md) | 覆盖物、热力、点聚合逻辑、轨迹、Marker | 与 annotations 组合使用 |
| [ui-standards.md](ui-standards.md) | 检索/路线/选点/弹窗/视野/Logo 等 UI 标准 | 无特殊要求时方案按此实现 |
| [search.md](search.md) | Sug、地理编码、逆地理、POI、公交 | 路线算路见 [route.md](route.md) |
| [route.md](route.md) | BMKRouteSearch：驾车/步行/骑行/公交算路与画线、BMKPlanNode、路况 | 与 walkcyclenavi 不同服务；仅算路+画线用本文档 |
| [navi.md](navi.md) | BaiduWalkNaviKit：步骑行实时导航、诱导、TTS、偏航、多实例、无UI | 与 route 不同服务；需实时导航用本文档 |
| [utils.md](utils.md) | BMKCoordTrans、BMKGeometry、视野、调起地图 | 工具类，与其它文档组合 |
| [assets.md](assets.md) | 图片资源 | 技能内 assets 目录 |
| [class-index.md](class-index.md) | 类与头文件速查 | 用法与示例见各功能文档 |

## 常见组合

| 需求 | 文档组合 |
|------|----------|
| 地图 + 定位 | cocoapods → project-config → mapview + location（坐标系统一 BD09） |
| 地图 + 路线画线 | mapview + route + search（选点）；步骑行仅画线用 route |
| 步骑行实时导航 | cocoapods（BaiduWalkNaviKit）→ project-config → navi |
| 标注 + 点聚合 | annotations + overlays（聚类与 Marker） |
| 定位鉴权失败 | [location.md](location.md)「鉴权失败排查」+ project-config 隐私与 Info.plist |


path: references/location.md
content: # 百度 iOS 定位 SDK（BMKLocationKit）

**边界**：单次/连续/后台/室内定位、地理围栏、鉴权；与地图独立，可单独或与 BaiduMapKit 配合。与地图混用须统一坐标系，见 [utils.md](utils.md)。不含步骑行导航内部定位。

## CocoaPods 集成

Pod 库名：**BMKLocationKit**。在 Podfile 同目录执行 `pod install`，使用生成的 `.xcworkspace` 打开工程。

```ruby
platform :ios, '9.0'
target 'YourProjectTarget' do  # 替换为工程名
  pod 'BMKLocationKit', '2.1.3'
end
```

常用命令：`pod install`、`pod repo update`、`pod update`。若 `pod search` 找不到类库：`pod setup` → 删除 `~/Library/Caches/CocoaPods/search_index.json` → 再执行 `pod search BMKLocationKit`。

## 隐私与初始化（必须遵守）

**必须通过 BMKLocationAuth 的 setAgreePrivacy 在用户同意隐私政策后再进行定位 SDK 的初始化。**

- 首次使用前弹窗让用户阅读并同意隐私政策（隐私政策地址可跳转：https://lbsyun.baidu.com/index.php?title=openprivacy）。
- 用户同意后调用 `[[BMKLocationAuth sharedInstance] setAgreePrivacy:YES]`，**再**初始化定位相关逻辑（如 BMKLocationManager 等）。
- 用户不同意时调用 `setAgreePrivacy:NO`，且不要初始化定位 SDK。
- 与地图 SDK 区分：地图使用 `[BMKMapManager setAgreePrivacy:YES]`；定位使用 **BMKLocationAuth** 的 setAgreePrivacy。

## 鉴权失败排查（无法返回定位/地址时）

若出现 **「鉴权失败导致无法返回定位、地址等信息」**（或错误码 BMKLocationErrorFailureAuth），按下列顺序检查：

| 排查项 | 说明 |
|--------|------|
| **1. setAgreePrivacy 顺序** | 必须在 **BMKLocationManager、BMKGeoFenceManager 等实例化之前** 调用 `[[BMKLocationAuth sharedInstance] setAgreePrivacy:YES]`。顺序：先 setAgreePrivacy(YES) → 再创建/初始化 BMKLocationManager → 再发起定位。若先初始化再设隐私，会导致鉴权失败。 |
| **2. AK（密钥）配置** | 在百度 LBS 控制台申请 **iOS 应用** 的 AK，且 **Bundle Identifier** 必须与当前应用一致。在任意定位 SDK 类初始化前完成 AK 校验/配置（如 BMKLocationAuth 的 checkPermisionWithKey: 等）。多应用需分别申请 AK。 |
| **3. 网络与权限** | 确认设备网络正常；确认已向用户申请并授予定位权限（Info.plist 配置 NSLocationWhenInUseUsageDescription 等）。 |

## 坐标系（与地图 SDK 一致）

**地图 SDK 全局使用 BD09**。**定位 SDK** 通过 **coordinateType**（类型 BMKLocationCoordinateType）设定定位坐标系，**默认为 BMKLocationCoordinateTypeGCJ02**。将定位结果用于地图展示、标注、路线或与地图 API 混用时，必须统一为 BD09：将 **coordinateType 设为 BMKLocationCoordinateTypeBMK09LL**，或使用地图 [utils.md](utils.md) 的 `BMKCoordTrans:fromType:toType:` 将 GCJ02 转为 BD09 后再传给地图。否则会出现偏移或错误。

## 核心类与接口（含默认值，避免与预期不一致）

### BMKLocationAuth

头文件：BMKLocationAuth.h。**初始化 BMKLocationManager 之前必须设置 BMKLocationAuth 中的 APIKey，否则无法正常使用服务。**

| 接口/属性 | 说明 |
|-----------|------|
| `sharedInstance` | 单例 |
| `setAgreePrivacy:` | 设置用户是否同意隐私政策，须在 BMKLocationManager/BMKGeoFenceManager 实例化前调用 |
| `checkPermisionWithKey:...` | AK 校验，须在任意定位 SDK 类使用前调用 |

---

### BMKLocationManager（类参考，含属性默认值）

头文件：BMKLocationManager.h。使用前须在 BMKLocationAuth 中设置 APIKey 并 setAgreePrivacy:YES。

#### 属性（含默认值）

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| delegate | id\<BMKLocationManagerDelegate\> | — | 连续定位/错误回调等 |
| distanceFilter | CLLocationDistance | **kCLDistanceFilterNone** | 定位最小更新距离 |
| headingFilter | CLLocationDegrees | **1**（since 2.0.5） | 设备朝向最小更新角度 |
| desiredAccuracy | CLLocationAccuracy | **kCLLocationAccuracyBest** | 定位精度 |
| activityType | CLActivityType | **CLActivityTypeAutomotiveNavigation** | 定位类型 |
| showsBackgroundLocationIndicator | BOOL | **NO**（iOS11+） | 后台定位时状态栏是否显示指示器；“始终授权”下设置有效 |
| coordinateType | BMKLocationCoordinateType | **BMKLocationCoordinateTypeGCJ02** | 定位坐标系类型。与地图混用须设为 BMKLocationCoordinateTypeBMK09LL |
| pausesLocationUpdatesAutomatically | BOOL | **NO** | 定位是否被系统自动暂停 |
| allowsBackgroundLocationUpdates | BOOL | **NO**（iOS9+） | 是否允许后台定位；设为 YES 时须开启 Background Modes → Location updates，且在定位未开始或已停止时修改才生效 |
| locationTimeout | NSInteger | **10**（秒） | 单次定位超时时间，最小 2s；在单次定位请求前设置；从定位权限非 NotDetermined 后开始计时 |
| reGeocodeTimeout | NSInteger | **10**（秒） | 单次逆地理超时时间，最小 2s；单次定位请求前设置 |
| locatingWithReGeocode | BOOL | **YES** | 连续定位是否返回逆地理信息 |
| isNeedNewVersionReGeocode | BOOL | **YES**（1.9 起） | 是否需要最新版逆地理数据（如城市变更实时更新） |
| userID | NSString * | — | 开发者指定用户 ID，便于排查问题 |
| accuracyAuthorization | BMKLAccuracyAuthorization | （只读） | 定位精度等级，iOS14+ 用户可控制；用于适配不同精度下的产品逻辑 |

#### 实例方法

| 方法 | 说明 |
|------|------|
| `requestLocationWithReGeocode:withNetworkState:completionBlock:` | 单次定位。正在连续定位时调用会失败返回 NO。按 desiredAccuracy 获取定位，精度不足会等待至超时后回调精度最高结果。可用 stopUpdatingLocation 取消。参数：withReGeocode 是否带逆地理（需联网），withNetWorkState 是否带移动热点识别（需联网） |
| `startUpdatingLocation` | 开始连续定位；会 cancel 所有单次定位请求 |
| `stopUpdatingLocation` | 停止连续定位；会 cancel 所有单次定位请求，也可用于取消单次定位 |
| `requestNetworkState` | 请求网络状态结果回调 |
| `startUpdatingHeading` | 开始设备朝向事件回调 |
| `stopUpdatingHeading` | 停止设备朝向事件回调 |
| `tryIndoorLocation` | 尝试高精度室内定位（仅室内定位版本生效） |
| `stopIndoorLocation` | 关闭高精度室内定位（仅室内定位版本生效） |
| `authorizationStatus` | 返回当前定位权限（CLAuthorizationStatus） |
| `requestTemporaryFullAccuracyAuthorizationWithPurposeKey:completion:` | 无全量精度权限时临时请求一次全量精度，系统弹框；purposeKey 对应 Info.plist 中 NSLocationTemporaryUsageDescriptionDictionary 的 key（iOS14+） |
| `requestTemporaryFullAccuracyAuthorizationWithPurposeKey:` | 请求一次全量定位精度等级（iOS14+） |

#### BMKLocationManagerDelegate 回调（头文件 BMKLocationManager.h）

| 方法 | 说明 |
|------|------|
| `BMKLocationManager:didUpdateLocation:` | 连续定位位置更新，location 为 BMKLocation |
| `BMKLocationManager:didFailWithError:` | 定位失败，error 含 BMKLocationErrorFailureAuth 等 |
| `BMKLocationManager:didUpdateHeading:` | 设备朝向更新（需先 startUpdatingHeading） |

单次定位结果在 `requestLocationWithReGeocode:...completionBlock:` 的 block 中返回。

#### 类方法

| 方法 | 说明 |
|------|------|
| `+ headingAvailable` | 设备是否支持朝向事件回调 |
| `+ BMKLocationCoordinateConvert:SrcType:DesType:` | 坐标转换。参数：coordinate 待转换经纬度，srctype 源坐标系类型，destype 目标百度坐标系类型（bd09ll、bd09mc）。返回目标百度坐标系经纬度 |
| `+ BMKLocationDataAvailableForCoordinate:withCoorType:` | 判断经纬度是否在大陆及港、澳地区。参数：coordinate 待判断经纬度，coortype 该经纬度的坐标系类型。返回 YES 表示境内 |

### BMKGeoFenceManager

地理围栏：创建、查询、删除围栏等，须在 setAgreePrivacy:YES 之后实例化。

**国内外/境内判断**：使用 `[BMKLocationManager BMKLocationDataAvailableForCoordinate:withCoorType:]`，coortype 传 [REDACTED_SECRET]，返回 YES 表示国内。与地图配合见 [utils.md](utils.md)。

## 获取位置信息（能力与对应方式）

| 能力 | 说明 |
|------|------|
| 单次定位 | BMKLocationManager 的 requestLocationWithReGeocode: completionBlock: |
| 连续定位 | startUpdatingLocation，通过 BMKLocationManagerDelegate 回调 |
| 后台定位 | allowsBackgroundLocationUpdates = YES，UIBackgroundModes 含 location，并配置 Info.plist 定位相关说明 |
| 室内定位 | 使用室内定位相关 API（具体见 BMKLocationKit 头文件） |

## 辅助功能（能力与对应类/接口）

| 能力 | 说明 |
|------|------|
| 地理围栏 | BMKGeoFenceManager，创建/删除围栏、状态回调 |
| 移动热点识别 | 定位 SDK 提供的热点相关接口 |
| 国内外位置判断 | BMKLocationManager 的 BMKLocationDataAvailableForCoordinate:withCoorType: |
| 坐标转换 | 定位 SDK 内坐标类型配置（coordinateType）或配合地图 utils 的 BMKCoordTrans |
| 防作弊 | 定位 SDK 提供的防作弊相关接口 |

错误码（如 BMKLocationErrorFailureAuth）、iOS 14 适配、提交 App Store 注意事项、HTTPS 等请查阅百度 LBS 开放平台 iOS 定位 SDK 文档。

## 与地图 SDK 的关系

- **仅需定位**：只集成 BMKLocationKit 即可。
- **地图 + 定位**：同时集成 BaiduMapKit 与 BMKLocationKit；地图上「我的位置」、定位图层等见 [mapview.md](mapview.md)（LocationViewAPI）；坐标转换、国内外判断等见 [utils.md](utils.md)。
- **隐私**：定位 SDK 必须通过 **BMKLocationAuth** 的 **setAgreePrivacy** 在用户同意后再初始化；地图 SDK 使用 BMKMapManager 的 setAgreePrivacy。详见上文「隐私与初始化」。

---

## 按需方案

| 需求 | 说明 |
|------|------|
| 仅需定位、无地图 | BMKLocationKit，BMKLocationAuth setAgreePrivacy → BMKLocationManager，coordinateType 按需设置 |
| 地图上显示我的位置 | BaiduMapKit + BMKLocationKit，mapview 的 showsUserLocation / userTrackingMode / updateLocationData；定位结果 coordinateType 建议 BMK09LL |
| 国内外/境内判断 | BMKLocationManager 的 BMKLocationDataAvailableForCoordinate:withCoorType:，见 [utils.md](utils.md) |
| 单次/连续/后台/室内定位 | BMKLocationManager requestLocationWithReGeocode、startUpdatingLocation、allowsBackgroundLocationUpdates 等 |
| 地理围栏/热点/坐标转换/防作弊 | BMKGeoFenceManager、coordinateType、及 SDK 对应辅助接口 |


path: references/utils.md
content: # 工具组件

**边界**：坐标转换、几何、视野、调起地图等；与其它文档组合使用。优先用本文 API，勿手写（见 [SKILL.md](../SKILL.md)）。

## 坐标转换 (BMKGeometry)

头文件：`BaiduMapAPI_Utils/BMKGeometry.h`

| 函数 | 说明 |
|------|------|
| `BMKMapPointForCoordinate:` | 经纬度 → 直角地理坐标 |
| `BMKCoordinateForMapPoint:` | 直角地理坐标 → 经纬度 |
| `BMKCoordTrans:fromType:toType:` | 经纬度坐标系转换（WGS84/GCJ02/BD09） |
| `BMKConvertToBaiduMercatorFromBD09LL:` | BD09 经纬度 → 百度墨卡托 |
| `BMKConvertToBD09LLFromBaiduMercator:` | 百度墨卡托 → BD09 经纬度 |

**坐标系类型**（BMKTypes.h）：`BMK_COORDTYPE_GPS`(WGS84)、`BMK_COORDTYPE_COMMON`(GCJ02)、`BMK_COORDTYPE_BD09LL`(百度)。**注意**：地图 SDK 全局为 BD09；定位 SDK 的 **coordinateType 默认为 BMKLocationCoordinateTypeGCJ02**，用于地图时需设为 BMKLocationCoordinateTypeBMK09LL 或先用 BMKCoordTrans 转换，见 [location.md](location.md)「坐标系」。

## 几何计算

| 函数 | 说明 |
|------|------|
| `BMKMetersPerMapPointAtLatitude:` | 指定纬度下 1 MapPoint 对应的米数 |
| `BMKMapPointsPerMeterAtLatitude:` | 指定纬度下 1 米对应的 MapPoint 数 |
| `BMKMetersBetweenMapPoints` | 两点间距离（米） |
| `BMKMetersBetweenCoordinates` | 两点间距离（米） |
| `BMKGetDirectionFromCoords` | 从起点到终点的方位角（0°=北，CLLocationDirection） |
| `BMKMapRectInset` | 矩形内缩 |
| `BMKMapRectUnion` | 矩形并集 |
| `BMKMapRectContainsPoint` | 点是否在矩形内 |

**大地线 slerp**（球面线性插值，SDK 未提供）：`f∈[0,1]` 时 `coord = slerp(from, to, f)` 沿大地线插值。将经纬度转单位球坐标 (x,y,z)，`dot = from·to`，`omega = acos(dot)`，`a = sin((1-f)*omega)/sin(omega)`，`b = sin(f*omega)/sin(omega)`，`p = a*from + b*to`，再转回经纬度。

## 动画插值器 (BMKInterpolator)

头文件：`BaiduMapAPI_Map/BMKInterpolator.h`

用于 BMKMapTrackAnimation 等动画的插值曲线：

| 类型 | 说明 |
|------|------|
| BMKLinearInterpolator | 线性（默认） |
| BMKAccelerateDecelerateInterpolator | 先加速后减速 |
| BMKAccelerateInterpolator | 加速 |
| BMKDecelerateInterpolator | 减速 |
| BMKAnticipateInterpolator | 回弹后前进 |
| BMKOvershootInterpolator | 超出后回弹 |
| BMKBounceInterpolator | 弹跳 |
| BMKCycleInterpolator | 正弦循环 |

## 调起百度地图

头文件：`BaiduMapAPI_Utils/BMKNavigation.h`、`BMKOpenPoi.h`、`BMKOpenRoute.h`

| 类 | 说明 |
|----|------|
| BMKNavigation | 调起百度地图导航 |
| BMKOpenPoi | 打开 POI 详情 |
| BMKOpenRoute | 打开路线规划 |
| BMKOpenPanorama | 打开街景 |

## 常用枚举 (BMKCommonDef)

头文件：`BaiduMapAPI_Map/BMKCommonDef.h`

| 枚举 | 说明 |
|------|------|
| BMKRotateAnmination | Marker 使用动画旋转 |
| BMKRotateItem | 使用外部设置的 rotate |
| BMKRotateGeoNorth | 旋转基准为地理北（与 BMKGetDirectionFromCoords 一致） |
| BMKRotateScreenUpper | 旋转基准为屏幕正上方 |
| BMKAnimationTrackXY | 轨迹动画跟随 X、Y |
| BMKFollowMapRotateAxisPitch | 跟随地图俯仰角 |
| BMKFollowMapRotateAxisYaw | 跟随地图偏航角 |

## 地图视野适配

根据 polyline 或 annotations 设置地图可见区域：

```objc
// 单条 polyline
- (void)mapViewFitPolyline:(BMKPolyline *)polyline withMapView:(BMKMapView *)mapView {
    if (polyline.pointCount < 1) return;
    BMKMapPoint pt = polyline.points[0];
    double leftTop_x = pt.x, leftTop_y = pt.y, rightBottom_x = pt.x, rightBottom_y = pt.y;
    for (int i = 1; i < polyline.pointCount; i++) {
        BMKMapPoint p = polyline.points[i];
        leftTop_x = MIN(leftTop_x, p.x);
        rightBottom_x = MAX(rightBottom_x, p.x);
        leftTop_y = MIN(leftTop_y, p.y);
        rightBottom_y = MAX(rightBottom_y, p.y);
    }
    BMKMapRect rect = BMKMapRectMake(leftTop_x, leftTop_y, rightBottom_x - leftTop_x, rightBottom_y - leftTop_y);
    [mapView fitVisibleMapRect:rect edgePadding:UIEdgeInsetsMake(20, 10, 20, 10) withAnimated:YES];
}

// 或使用 showAnnotations:padding:animated:
[mapView showAnnotations:mapView.annotations padding:UIEdgeInsetsMake(0, 50, 0, 40) animated:YES];

// 视野适配标准见 ui-standards.md
```

### 全点视野适配（标注 + 路线途经点）

当标注与路线途经点分布较广时，`showAnnotations` 仅适配标注，可能遗漏路线点。应在 **mapViewDidFinishLoading** 中收集所有坐标，用 `BMKMapPointForCoordinate` + `BMKMapRectUnion` 构建 BMKMapRect，再调用 `fitVisibleMapRect`：

```objc
- (void)fitMapToAllPoints {
    NSMutableArray<NSValue *> *allCoords = [NSMutableArray array];
    for (id<BMKAnnotation> ann in self.mapView.annotations) {
        CLLocationCoordinate2D c = ann.coordinate;
        [allCoords addObject:[NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]];
    }
    for (MarchRouteModel *route in routes) {
        for (NSValue *v in route.waypoints) { [allCoords addObject:v]; }
    }
    if (allCoords.count == 0) return;
    CLLocationCoordinate2D first; [allCoords.firstObject getValue:&first];
    BMKMapRect rect = BMKMapRectMake(BMKMapPointForCoordinate(first).x, BMKMapPointForCoordinate(first).y, 0, 0);
    for (NSValue *v in allCoords) {
        CLLocationCoordinate2D c; [v getValue:&c];
        rect = BMKMapRectUnion(rect, BMKMapRectMake(BMKMapPointForCoordinate(c).x, BMKMapPointForCoordinate(c).y, 0, 0));
    }
    [self.mapView fitVisibleMapRect:rect edgePadding:UIEdgeInsetsMake(100, 44, bottomPad + 44, 44) withAnimated:YES];
}
```

---

## 按需方案

| 需求 | 能力 | 说明 |
|------|------|------|
| 路线全屏可见 | fitVisibleMapRect / showAnnotations | 本文 |
| 坐标转换 | BMKCoordTrans、BMKMapPointForCoordinate | 本文 |
| 国内外/境内判断 | 百度 **iOS 定位 SDK** | **最佳**：`[BMKLocationManager BMKLocationDataAvailableForCoordinate:withCoorType:]`，坐标类型 BMKLocationCoordinateTypeBMK09LL，返回 YES=国内。未集成定位 SDK 时可用多矩形或逆地理（BMKReverseGeoCodeSearch）辅助。 |
| 调起百度地图导航 | BMKNavigation | 本文 |


path: references/overlays.md
content: # 覆盖物 (Overlay)

**边界**：addOverlay 体系；标注见 [annotations.md](annotations.md)，地图 API 见 [mapview.md](mapview.md)。**必须遵守**：点标注**优先使用 Marker**（本 addOverlay 体系），不得使用 BMKPointAnnotation/BMKPinAnnotationView，除非点聚合、固定屏选点等例外。见 [SKILL.md](../SKILL.md) 规则 3。

## 路线与起终点：纹理优先（必须遵守）

**绘制路线与起终点覆盖物时，须优先使用纹理，仅无可用纹理时再使用纯色或自绘。**

- **路线折线**
  - 单色/单纹理：`BMKPolyline` + `BMKPolylineView`。**优先**设置 `view.textureImage`（图片宽高须为 2 的 n 次幂），无纹理时再设 `view.strokeColor`。线宽 8pt，见 [ui-standards.md](ui-standards.md)。
  - 路况分段：`BMKMultiPolyline` + `BMKMultiTexturePolylineView`，`textureImages` 使用 [assets](assets.md) 提供的 traffic_texture_* 等。
- **起终点 Marker**
  - `BMKIconMarker.icon` **须优先**使用 [assets](assets.md) 的 **icon_start**（起点）、**icon_end**（终点）；实现时先 `[UIImage imageNamed:@"icon_start"]` / `imageNamed:@"icon_end"`，为 nil 再回退到自绘或纯色。
- **小车图标**：见 [SKILL.md](../SKILL.md) 规则 3「路线小车纹理」及 [assets](assets.md)。

生成或修改覆盖物相关代码时，**必须先检查并应用上述纹理优先**，避免仅写 strokeColor/自绘导致规范未生效。

## 使用须知
- **Delegate**：addOverlay 前必须设置 `mapView.delegate`，并实现 `mapView:viewForOverlay:`。
- **批量添加**：`addOverlays:` 可一次添加多个 overlay。
- **起终点推荐 BMKIconMarker**：添加顺序为路线→起终点→小车。起终点 icon 须优先使用 [assets](assets.md) 的 icon_start/icon_end；小车图标须优先使用技能 [assets](assets.md) 纹理（icon_car 等），无则再颜色/自绘。样式见 [ui-standards.md](ui-standards.md)。
- **步骑行多路线折线**：BaiduWalkNaviKit 的 `displayRoutePlanResult:mapView` 返回 `NSArray<BMKPolyline *>`；若由业务侧 addOverlay，需在 `mapView:viewForOverlay:` 中对 `BMKPolyline` 返回 `BMKPolylineView`（如 textureImage 或 strokeColor、lineWidth），否则路线不显示。

## 示例：添加折线（Overlay，addOverlay）

需实现 `mapView:viewForOverlay:`，根据 overlay 类型返回对应 View。

```objc
CLLocationCoordinate2D coords[2] = {
    CLLocationCoordinate2DMake(39.915, 116.404),
    CLLocationCoordinate2DMake(39.920, 116.410)
};
BMKPolyline *polyline = [BMKPolyline polylineWithCoordinates:coords count:2];
[mapView addOverlay:polyline];

#pragma mark - BMKMapViewDelegate
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
    if ([overlay isKindOfClass:[BMKPolyline class]]) {
        BMKPolylineView *view = [[BMKPolylineView alloc] initWithOverlay:overlay];
        // 纹理优先：有纹理图时设置 textureImage（宽高须 2 的 n 次幂），无则 strokeColor
        UIImage *tex = [UIImage imageNamed:@"route_texture"];  // 示例；可用 assets 或自备
        if (tex) view.textureImage = tex;
        else view.strokeColor = [UIColor blueColor];
        view.lineWidth = 8.0f;  // 路线线宽 8pt，见 ui-standards
        return view;
    }
    return nil;
}
```

## 示例：添加图标 Marker（Overlay，addOverlay）

点标注推荐用 BMKIconMarker（addOverlay），与地图坐标系一致；anchor 沿路线居中时设 0.5/0.5。

```objc
BMKIconMarker *marker = [[BMKIconMarker alloc] init];
marker.coordinate = CLLocationCoordinate2DMake(39.915, 116.404);
// 起终点纹理优先：起点用 icon_start，终点用 icon_end，无则回退自绘/纯色
marker.icon = [UIImage imageNamed:@"icon_start"];  // 或 icon_end / icon_pin
if (!marker.icon) marker.icon = [self drawDefaultPinImage];  // 回退
marker.anchorX = 0.5;  // 沿路线居中时 0.5/0.5，否则默认 anchorY=1 坐标在底部中心
marker.anchorY = 0.5;
[mapView addOverlay:marker];

#pragma mark - BMKMapViewDelegate
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
    if ([overlay isKindOfClass:[BMKIconMarker class]]) {
        BMKIconMarkerView *view = [[BMKIconMarkerView alloc] initWithOverlay:overlay];
        view.isClickable = YES;  // 点击触发 mapView:onClickedBMKOverlayView:
        return view;
    }
    return nil;
}
```

## 常用默认值（易导致不生效或与预期不符）

以下为地图/覆盖物相关类常见默认值，未显式设置时可能造成行为差异，建议按需显式赋值。

| 类/接口 | 属性/方法 | 默认值 | 说明 |
|---------|-----------|--------|------|
| BMKMapTrackAnimation | setTrackPosRadio | **0.0 ~ 0.0**（无有效范围） | 轨迹动画**必须**显式调用 `setTrackPosRadio:0.0 to:1.0`，否则无有效播放范围 |
| BMKMapTrackAnimation / BMKMapAnimationSet | start | **不自动 start** | 需手动调用 `start`；其他动画类型默认自动 start |
| BMKIconMarker | anchorX / anchorY | **0.5 / 1.0** | 坐标在图标底部中心；沿路线居中时设 0.5/0.5 |
| BMKMultiColorPolylineView | lineCapType | **kBMKLineCapButt** | 不支持虚线；kBMKLineCapRound 支持虚线 |
| BMKMapView | setMapStatus:withAnimation: | 动画时长为 SDK 默认 | 需指定时长时用 `setMapStatus:withAnimation:withAnimationTime:`（单位 ms） |
| 定位 SDK（BMKLocationManager） | coordinateType | **BMKLocationCoordinateTypeGCJ02** | 与地图（BD09）混用时须设为 BMK09LL 或做转换，见 [location.md](location.md) |

## 覆盖物

### 基础覆盖物

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKOverlay | BMKOverlay.h | 覆盖物协议 |
| BMKOverlayView | BMKOverlayView.h | 覆盖物视图基类 |
| BMKPolyline | BMKPolyline.h | 单色/单纹理折线 |
| BMKPolylineView | BMKPolylineView.h | 折线视图，支持 textureImage、lineDashType |
| BMKMultiPolyline | BMKMultiPolyline.h | 分段折线，需 drawIndexs |
| BMKMultiColorPolylineView | BMKMultiPolylineView.h | 分段颜色 |
| BMKMultiTexturePolylineView | BMKMultiPolylineView.h | 分段纹理（路况） |
| BMKCircle | BMKCircle.h | 圆形 |
| BMKCircleView | BMKCircleView.h | 圆形视图 |
| BMKPolygon | BMKPolygon.h | 多边形 |
| BMKPolygonView | BMKPolygonView.h | 多边形视图 |
| BMKGroundOverlay | BMKGroundOverlay.h | 图片图层 |
| BMKGroundOverlayView | BMKGroundOverlayView.h | 图片图层视图 |

**折线**：`BMKPolyline polylineWithCoordinates:count:`。`BMKPolylineView.textureImage` 要求图片宽高为 2 的 n 次幂。**路线线宽**标准 **8pt**，见 [ui-standards.md](ui-standards.md)。`lineDashType`：`kBMKLineDashTypeDot`（圆点虚线）、`kBMKLineDashTypeSquare` 等。

**分段折线**：`BMKMultiPolyline multiPolylineWithCoordinates:count:drawIndexs:`，drawIndexs 为 NSNumber 数组，对应 strokeColors 或 textureImages 索引。`BMKMultiColorPolylineView.lineCapType` 默认 `kBMKLineCapButt`（不支持虚线），`kBMKLineCapRound` 支持。`BMKMultiTexturePolylineView.lineJoinType`：`kBMKLineJoinRound`/`Bevel`/`Miter`。

**镂空**：BMKCircle、BMKPolygon 支持 `hollowShapes`，可传入 BMKCircle、BMKPolygon 数组实现镂空。

**圆形**：`BMKCircle circleWithCenterCoordinate:radius:`，radius 单位米。BMKCircleView 设置 `fillColor`、`strokeColor`、`lineWidth`。

**多边形**：`BMKPolygon polygonWithCoordinates:count:`。BMKPolygonView 支持 `lineDashType`。

**图片图层**：`BMKGroundOverlay groundOverlayWithBounds:icon:`（BMKCoordinateBounds：southWest、northEast）；或 `groundOverlayWithPosition:zoomLevel:anchor:icon:`。`alpha` 控制透明度 [0, 1]。

### 曲线与渐变

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKArcline | BMKArcline.h | 圆弧（3 点确定） |
| BMKArclineView | BMKArclineView.h | 圆弧视图 |
| BMKGradientLine | BMKGradientLine.h | 渐变线 |
| BMKGradientLineView | BMKGradientLineView.h | 渐变线视图 |
| BMKGradientCircleView | BMKGradientCircleView.h | 渐变圆（BMKCircle + 渐变） |
| BMKGeodesicLine | BMKGeodesicLine.h | 大地线（球面最短路径） |
| BMKGeodesicLineView | BMKGeodesicLineView.h | 大地线视图 |

**圆弧**：`BMKArcline arclineWithCoordinates:` 需传入 3 个点。

**渐变线**：`BMKGradientLine gradientLineWithCoordinates:count:drawIndexs:`，用法类似 BMKMultiPolyline。BMKGradientLineView 设置 `strokeColors`、`lineWidth`。

**渐变圆**：BMKGradientCircleView 用 `initWithOverlay:` 传入 BMKCircle。`radiusWeight`、`colorWeight` 控制渐变规则；`centerColor`、`sideColor` 为渐变起止色。

**大地线**：`BMKGeodesicLine geodesicLineWithCoordinates:count:`。经度跨 180° 时须设置 `lineDirectionCross180`（如 [REDACTED_SECRET]）。**沿大地线模拟移动**：用球面线性插值 slerp 从 origin 到 dest，`coord = slerp(origin, dest, progress)`；`BMKGetDirectionFromCoords(current, slerp(origin,dest, progress+0.02))` 得切线方向。往返飞行：`routeDirection` 1 或 -1 切换，回程 `coord = slerp(dest, origin, 1-progress)`。slerp 公式见 [utils.md](utils.md)。

### Marker 类（addOverlay）

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKIconMarker | BMKIconMarker.h | 图标 Marker |
| BMKIconMarkerView | BMKIconMarkerView.h | 图标 Marker 视图 |
| BMKTextMarker | BMKTextMarker.h | 文本 Marker |
| BMKTextMarkerView | BMKTextMarkerView.h | 文本 Marker 视图 |
| BMKTextPathMarker | BMKTextPathMarker.h | 沿路径文字 |
| BMKTextPathMarkerView | BMKTextPathMarkerView.h | 沿路径文字视图 |

**BMKIconMarker**：`icon` 单图，`icons` 图片组（按间隔轮播）。`scaleX`/`scaleY`、`anchorX`/`anchorY`（默认 0.5/1.0）。**沿路线居中**：设置 `anchorX = 0.5`、`anchorY = 0.5`，否则默认 anchorY=1 使坐标在图标底部中心，圆心会偏上。`addRichView:` 挂接 BMKRichView（BMKImageUIView、BMKLabelUIView、BMKVerticalLayout、BMKHorizontalLayout），RichView 无坐标，必须挂到 marker 上。

**BMKIconMarker 旋转**：`marker.rotateFeature = BMKRotateItem | BMKRotateGeoNorth`（地理北为基准，与 BMKGetDirectionFromCoords 一致）。基准图标建议机头朝上，`marker.rotate = heading`；若方向相反可试 `rotate = -heading` 或 `heading ± 90`。沿大地线移动时用「当前点→路径稍前点」算切线：`BMKGetDirectionFromCoords(current, slerpCoord(origin,dest, progress+0.02))`。

**BMKRichView 示例**：BMKLabelUIView + BMKTextStyle + BMKVerticalLayout，`richView.locate = BMKLocateBottom`、`offsetY` 控制位置。`rootView = layout`，`[marker addRichView:richView]`。

**碰撞检测**：`marker.collisionBehavior = BMKCollisionWithInner | BMKCollisionHideByPriority`，`collisionPriority` 越大越不易被遮挡。RichView 同理。**注意**：动画中暂不支持，定时器驱动的位置更新可生效。

**BMKTextMarker**：`text`、`style`（BMKTextStyle：fontSize、fontOption、borderWidth、textColor、borderColor）。

**BMKTextPathMarker**（路线路名沿路径绘制）：用 `textPathMarkerWithPoints:count:` 或 `textPathMarkerWithCoordinates:count:` 传入路径点（如 BMKDrivingStep 的 points/count），再设 `text`（路名）、`style`（BMKTextStyle，如 22pt 黑字白边见 [ui-standards.md](ui-standards.md)）。View 为 **BMKTextPathMarkerView**，`initWithMarker:` 传入 marker。路线规划时每段 step 若有 `roadName` 可创建一条 BMKTextPathMarker 沿该 step 的 points 绘制，路名随路径走向展示。

**动画**：BMKMapScaleAnimation、BMKMapRotateAnimation、BMKMapAlphaAnimation、BMKMapAnimationSet。BMKMapTrackAnimation、BMKMapAnimationSet 默认不自动 start，其他动画默认自动 start。`addAnimation:addAnimationSetOrderType:` 支持 `BMKAnimationSetOrderTypeWith`（并行）、`BMKAnimationSetOrderTypeThen`（串行）。

**轨迹动画（BMKMapTrackAnimation）**：polyline 与 BMKIconMarker **必须共用同一 trackAnim**，否则小车不显示；只 `start` 一次。路线推荐 BMKMultiPolyline + BMKMultiTexturePolylineView；Forward=未走过（原色），Backward=已走过（灰度）。**走过置灰**（BMKGeometryView）：`strokeColorProgressForward`=原色（未走过）、`strokeColorProgressBackward`=灰色（已走过）；模拟导航同此。轨迹回放相反。驾车路况：drawIndexs 来自 traffics，textureImages 5 种（0 无数据/1 畅通/2 缓行/3 拥堵/4 严重拥堵），见 [assets.md](assets.md)。停止仅 `cancel`，勿解绑 overlay.animation。

**动画不显示时排查**（不建议用 CADisplayLink 等手动方案替代）：

| 检查项 | 说明 |
|--------|------|
| 共用同一实例 | `polyline.animation` 与 `marker.animation` 必须指向**同一个** BMKMapTrackAnimation |
| setTrackLine | 调用 `[trackAnim setTrackLine:polyline]`；部分场景需**先 addOverlay:polyline 再 setTrackLine** |
| setTrackPosRadio | **必须**调用 `[trackAnim setTrackPosRadio:0.0 to:1.0]`，默认 0~0 无有效范围 |
| 添加顺序 | 先 `addOverlay:polyline`，再 `addOverlay:marker` |
| trackBy | marker 设置 `trackBy = BMKAnimationTrackXY`；可加 `BMKAnimationTrackForward` 尝试使机头沿线段前进方向旋转（效果因场景而异，若方向仍不对改用 BMKRotateItem 手动计算 heading） |
| 只 start 一次 | 对所有 trackAnim 只调用一次 `start`；可 `dispatch_async` 到下一 RunLoop |
| polyline.isThined | 设为 NO，避免抽稀导致轨迹点丢失 |
| 参考 Demo | 对照官方 `BMKPolylineMarkerTeackAnimationPage.mm` |

**点击**：`BMKIconMarkerView`/`BMKTextMarkerView.isClickable = YES` 后，点击触发 `mapView:onClickedBMKOverlayView:`。

### 文本与海量点

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKText | BMKText.h | 文本 overlay（中心+文字） |
| BMKTextView | BMKTextView.h | 文本 overlay 视图 |
| BMKMultiPointOverlay | BMKMultiPointOverlay.h | 海量点 |
| BMKMultiPointOverlayView | BMKMultiPointOverlayView.h | 海量点视图 |
| BMKMultiPointItem | BMKMultiPointOverlay.h | 海量点数据项 |

**BMKText**：`textWithCenterCoordinate:text:`。BMKTextView 设置 `textColor`、`backgroundColor`、`fontSize`、`textFontType`、`textAlignment`、`textMaxLineWidth`、`textLineSpacing`、`textParagraphSpacing`、`textLineBreakMode`。点击回调 `mapView:onClickedBMKOverlayView:`。

**海量点**：`BMKMultiPointOverlay multiPointOverlayWithMultiPointItems:`。BMKMultiPointOverlayView 设置 `icon`、`anchor`、`pointSize`、`delegate`。BMKMultiPointOverlayViewDelegate 的 `didItemTapped:` 处理点击。

### 点聚合（SDK 未内置，参考 BMKPointCluster Demo）

将大量 BMKPointAnnotation 按地理距离聚合，zoom 小时显示聚合点（带数量），zoom 大时拆分为单点。**核心类**：BMKClusterManager、BMKClusterQuadtree、BMKQuadItem、BMKCluster。**流程**：坐标→BMKQuadItem 加入 quadtree；`getClusters:zoomLevel` 按 zoom 获取聚合；`clusterCaches[zoom-3]` 缓存；`mapViewDidFinishLoading` 与 `onDrawMapFrame`（zoom 变化时）触发 updateClusters。**标注展示**见 [annotations.md](annotations.md)。

### 3D 与轨迹

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMK3DModelOverlay | BMK3DModelOverlay.h | 3D 模型 |
| BMK3DModelOverlayView | BMK3DModelOverlayView.h | 3D 模型视图 |
| BMKPrismOverlay | BMKPrismOverlay.h | 棱柱/3D 建筑 |
| BMKPrismOverlayView | BMKPrismOverlayView.h | 棱柱视图 |
| BMKTraceOverlay | BMKTraceOverlay.h | 路书轨迹（发光、渐变色） |
| BMKTraceOverlayView | BMKTraceOverlayView.h | 路书轨迹视图 |
| BMK3DTraceOverlay | BMK3DTraceOverlay.h | 3D 轨迹 |
| BMK3DTraceOverlayView | BMK3DTraceOverlayView.h | 3D 轨迹视图 |

**3D 模型**：`BMK3DModelOverlay modelOverlayWithCenterCoordinate:option:`。BMK3DModelOption：`modelName`、`modelPath`、`scale`、`type`（BMK3DModelTypeGLTF）、`zoomFixed`、`rotateX`、`animationIsEnable`、`animationIndex`、`animationSpeed`、`animationRepeatCount`。3D 展示标准见 [ui-standards.md](ui-standards.md)。

**棱柱**：`BMKPrismOverlay prismOverlayWithPoints:count:` 传入 BMKMapPoint 数组，`height` 设高度。BMKPrismOverlayView 设置 `sideFaceColor`、`topFaceColor`。可用 BMKDistrictSearch 获取区域边界转 BMKMapPoint。

**3D 轨迹**：`BMK3DTraceOverlay traceOverlay3DWithCoordinates:count:option:`。BMK3DTraceOverlayOption：`traceType`、`duration`、`easingCurve`、`opacity`、`paletteOpacity`、`paletteImage`、`projectionPaletteImage`。BMK3DTraceOverlayView 的 `strokeHeights` 长度须与轨迹点数一致。BMK3DTraceOverlayAnimationDelegate 监听动画开始、进度、结束、实时位置。

**BMKTraceOverlay**：`traceOverlayWithCoordinates:count:option:`。Option：`animate=YES`、`trackMove=YES`、`isRotateWhenTrack=YES`、`pointMove=YES`。**pointImage 箭头尖端须朝右**，SDK 旋转后指向行进方向；建议 80×80。BMKTraceOverlayView 设置 `strokeColors`、`strokeColor`、`fillColor`。

**BMKMapTrackAnimation 图标**：polyline 与 BMKIconMarker 共用同一 trackAnim。marker 设置 `anchorX=0.5`、`anchorY=0.5`。**优先使用图片资源**（如 [assets.md](assets.md) 的 track_car 等），不合适时再自绘。旋转以图像**右侧**为行进方向。自绘时：40×40 画布，箭头尖端朝右；UIBezierPath 尖端在 `CGRectGetMaxX(rect) - w*0.05`，底座在左，`baseX + w*0.25` 为左侧凹进形成箭尾。

### 热力图（addHeatMap，非 overlay）

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKHeatMap | BMKHeatMap.h | 热力图 |
| BMKHexagonHeatMap | BMKHexagonHeatMap.h | 六边形热力图 |

**BMKHeatMap**：`mDatas` 为 BMKHeatMapNode 二维数组（支持帧动画），`mMaxHight`、`mGradient`（BMKGradient）、`animation`、`frameAnimation`、`delegate`。`addHeatMap`/`removeHeatMap`。`startHeatMapFrameAnimation`/`stopHeatMapFrameAnimation`/`setHeatMapFrameAnimationIndex:`。

**BMKHexagonHeatMap**：`mData`、`mRadius`、`mOpacity`、`mMaxIntensity`、`mGap`、`mHexagonType`（BMKHexagonTypeVertexUp）、`mGradient`。`addHexagonHeatMap`/`removeHexagonHeatMap`。

### 自定义 Overlay

继承 BMKShape，实现 `boundingMapRect`（用 BMKMapRect 包住所有点）。CustomOverlayView 继承 BMKOverlayView，重载 `glRender`。坐标用 `BMKMapPointForCoordinate` 转换。绘制：`renderLinesWithPoints:pointCount:strokeColor:lineWidth:looped:lineDashType:`、`renderRegionWithPoints:pointCount:fillColor:usingTriangleFan:`、`loadStrokeTextureImage:` + `renderTexturedLinesWithPoints:...`。纹理图片宽高须为 2 的 n 次幂。

## 坐标与结构体

| 类型 | 说明 |
|------|------|
| CLLocationCoordinate2D | 经纬度（BD09） |
| BMKMapRect | 直角地理坐标矩形 |
| BMKMapPoint | 直角地理坐标点 |
| BMKCoordinateRegion | 经纬度区域 |
| BMKCoordinateBounds | 经纬度边界（southWest、northEast） |

**坐标转换**（BMKGeometry.h）：`BMKMapPointForCoordinate`、`BMKCoordinateForMapPoint`。自定义 overlay 用 BMKMapPoint 计算 boundingMapRect。

---

## 按需方案

| 需求 | 基础能力 |
|------|----------|
| 起终点标记（推荐） | BMKIconMarker + addOverlay 顺序 |
| 起终点大头针 | BMKPointAnnotation + BMKAnnotationView，见 [annotations.md](annotations.md) |
| 单色路线 | BMKPolyline + BMKPolylineView，lineWidth 8pt（见 ui-standards） |
| 路况路线 | BMKMultiPolyline + BMKMultiTexturePolylineView，lineWidth 8pt（见 ui-standards） |
| 路线路名 | BMKTextPathMarker + BMKTextPathMarkerView（沿 step 路径绘制 roadName） |
| 路线动画 | BMKMapTrackAnimation + BMKPolyline/MultiPolyline + BMKIconMarker（共用 trackAnim） |
| 圆弧 | BMKArcline + BMKArclineView |
| 渐变线 | BMKGradientLine + BMKGradientLineView |
| 渐变圆 | BMKCircle + BMKGradientCircleView |
| 大地线 | BMKGeodesicLine + BMKGeodesicLineView |
| 图标按行进方向旋转 | BMKRotateItem \| BMKRotateGeoNorth + rotate |
| 航班/信息标签 | BMKRichView + BMKLabelUIView + BMKVerticalLayout |
| 重叠时隐藏 | collisionBehavior + collisionPriority |
| 沿大地线移动/往返 | slerp + BMKGetDirectionFromCoords + routeDirection |
| 文本 overlay | BMKText + BMKTextView |
| 海量点 | BMKMultiPointOverlay + BMKMultiPointItem |
| 点聚合（海量标注） | BMKClusterManager + BMKClusterQuadtree + BMKPointAnnotation |
| 3D 模型 | BMK3DModelOverlay + BMK3DModelOption |
| 棱柱/建筑 | BMKPrismOverlay + BMKPrismOverlayView |
| 路书轨迹 | BMKTraceOverlay + BMKTraceOverlayOption |
| 3D 轨迹 | BMK3DTraceOverlay + BMK3DTraceOverlayOption |
| 热力图 | BMKHeatMap + addHeatMap |
| 六边形热力图 | BMKHexagonHeatMap + addHexagonHeatMap |


path: references/annotations.md
content: # 标注 (Annotation)

**边界**：addAnnotation 体系；覆盖物见 [overlays.md](overlays.md)。**必须遵守**：点标注**优先使用 Marker**（BMKIconMarker/BMKTextMarker，addOverlay），**不得使用** Annotation/PinAnnotation 做起终点、小车、普通图钉等；**仅**点聚合、固定屏选点等必须用 addAnnotation 的场景才用本 API。见 [SKILL.md](../SKILL.md) 规则 3。

## 使用须知
- **Delegate**：addAnnotation 前必须设置 `mapView.delegate`，并实现 `mapView:viewForAnnotation:`。
- **复用**：使用 `dequeueReusableAnnotationViewWithIdentifier`，identifier 建议唯一。
- **起终点**：推荐 BMKIconMarker（addOverlay），见 [overlays.md](overlays.md)。

## 核心类

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKAnnotation | BMKAnnotation.h | 标注协议，`coordinate`、`title` |
| BMKPointAnnotation | BMKPointAnnotation.h | 点标注 |
| BMKAnnotationView | BMKAnnotationView.h | 标注视图基类 |
| BMKPinAnnotationView | BMKPinAnnotationView.h | 大头针样式 |
| BMKActionPaopaoView | BMKActionPaopaoView.h | 气泡视图 |

**标注规范**：使用 `dequeueReusableAnnotationViewWithIdentifier` 复用，identifier 建议唯一。自定义图片用 BMKAnnotationView + image。

## 固定屏幕标注（地图选点）

`BMKPointAnnotation.isLockedToScreen = YES` + `screenPointToLock`，需在 `mapViewDidFinishLoading` 后设置。常用于地图选点。

**方式 B（BMKIconMarker）**：Marker 无 isLockedToScreen，需在 `regionDidChangeAnimated:reason:` 中（reason == BMKRegionChangeReasonGesture）同步 `marker.coordinate = mapView.centerCoordinate`。**区域回调**：regionWillChange 跳起，regionDidChange 落下 + 逆地理。**选点动画**见 [ui-standards.md](ui-standards.md)。

## BMKPinAnnotationView 常用属性

`centerOffset`、`calloutOffset`（正偏移朝右下方）、`enabled3D`、`canShowCallout`、`leftCalloutAccessoryView`/`rightCalloutAccessoryView`（默认气泡最大 32×41）、`pinColor`（Red/Green/Purple）、`animatesDrop`、`draggable`。直接设置 `selected` 时，非 PinAnnotation 需在设置后调用 `mapForceRefresh`。

## 碰撞检测与展示优先级

`BMKAnnotationView.displayPriority`（如 `BMKFeatureDisplayPriorityDefaultHigh`）、`isOpenCollisionDetection`、`collisionDetectionPriority`（数值越大越优先）、`isForceDisplay`（强制展示）、`displayMaxLevel`/`displayMinLevel`（层级限制）。

## 点聚合中的标注

点聚合（BMKClusterManager + BMKPointAnnotation）将大量标注按 zoom 聚合。`viewForAnnotation` 按 cluster.size 区分单点/聚合点；size>1 可显示数量、按档设圆点大小。**点击拆簇**：`annotationViewForBubble` 中 zoomIn。聚合逻辑见 [overlays.md](overlays.md)。

---

## 按需方案

| 需求 | 基础能力 |
|------|----------|
| 普通点标注 | BMKPointAnnotation + BMKAnnotationView |
| 大头针 | BMKPointAnnotation + BMKPinAnnotationView |
| 固定屏幕选点 | BMKPointAnnotation（isLockedToScreen + screenPointToLock）或 BMKIconMarker |
| 起终点大头针 | BMKPointAnnotation + BMKAnnotationView（起终点推荐 BMKIconMarker，见 [overlays.md](overlays.md)） |
| 点聚合标注 | BMKClusterManager + BMKPointAnnotation，viewForAnnotation 按 size 展示 |


path: references/class-index.md
content: # 类速查表

**边界**：按头文件组织的类速查；用法与示例见 [annotations.md](annotations.md)、[overlays.md](overlays.md) 等各功能文档。下表记录类名、头文件及主要方法/属性名，便于不依赖外链查阅。

## 地图核心

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKMapManager | BMKMapManager.h | 主引擎 |
| BMKMapView | BMKMapView.h | 地图视图 |
| BMKMapStatus | BMKMapStatus.h | 地图状态 |
| BMKMapViewDelegate | BMKMapView.h | 地图回调 |

## 标注

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKAnnotation | BMKAnnotation.h | 标注协议 |
| BMKPointAnnotation | BMKPointAnnotation.h | 点标注 |
| BMKAnnotationView | BMKAnnotationView.h | 标注视图基类 |
| BMKPinAnnotationView | BMKPinAnnotationView.h | 大头针样式 |
| BMKActionPaopaoView | BMKActionPaopaoView.h | 气泡视图 |

## 覆盖物

### 基础

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKOverlay | BMKOverlay.h | 覆盖物协议 |
| BMKOverlayView | BMKOverlayView.h | 覆盖物视图基类 |
| BMKPolyline | BMKPolyline.h | 单色/单纹理折线 |
| BMKPolylineView | BMKPolylineView.h | 折线视图 |
| BMKMultiPolyline | BMKMultiPolyline.h | 分段折线，需 drawIndexs |
| BMKMultiColorPolylineView | BMKMultiPolylineView.h | 分段颜色 |
| BMKMultiTexturePolylineView | BMKMultiPolylineView.h | 分段纹理（路况） |
| BMKCircle | BMKCircle.h | 圆形 |
| BMKCircleView | BMKCircleView.h | 圆形视图 |
| BMKPolygon | BMKPolygon.h | 多边形 |
| BMKPolygonView | BMKPolygonView.h | 多边形视图 |
| BMKGroundOverlay | BMKGroundOverlay.h | 图片图层 |
| BMKGroundOverlayView | BMKGroundOverlayView.h | 图片图层视图 |
| BMKTileLayer | BMKTileLayer.h | 瓦片图层基类 |
| BMKURLTileLayer | BMKTileLayer.h | URL 瓦片图层 |

### 曲线与渐变

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKArcline | BMKArcline.h | 圆弧 |
| BMKArclineView | BMKArclineView.h | 圆弧视图 |
| BMKGradientLine | BMKGradientLine.h | 渐变线 |
| BMKGradientLineView | BMKGradientLineView.h | 渐变线视图 |
| BMKGradientCircleView | BMKGradientCircleView.h | 渐变圆 |
| BMKGeodesicLine | BMKGeodesicLine.h | 大地线 |
| BMKGeodesicLineView | BMKGeodesicLineView.h | 大地线视图 |

### Marker

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKIconMarker | BMKIconMarker.h | 图标 Marker |
| BMKIconMarkerView | BMKIconMarkerView.h | 图标 Marker 视图 |
| BMKTextMarker | BMKTextMarker.h | 文本 Marker |
| BMKTextMarkerView | BMKTextMarkerView.h | 文本 Marker 视图 |
| BMKTextPathMarker | BMKTextPathMarker.h | 沿路径文字 |
| BMKTextPathMarkerView | BMKTextPathMarkerView.h | 沿路径文字视图 |

### 文本与海量点

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKText | BMKText.h | 文本 overlay |
| BMKTextView | BMKTextView.h | 文本 overlay 视图 |
| BMKMultiPointOverlay | BMKMultiPointOverlay.h | 海量点 |
| BMKMultiPointOverlayView | BMKMultiPointOverlayView.h | 海量点视图 |
| BMKMultiPointItem | BMKMultiPointOverlay.h | 海量点数据项 |

### 3D 与轨迹

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMK3DModelOverlay | BMK3DModelOverlay.h | 3D 模型 |
| BMK3DModelOverlayView | BMK3DModelOverlayView.h | 3D 模型视图 |
| BMKPrismOverlay | BMKPrismOverlay.h | 棱柱/3D 建筑 |
| BMKPrismOverlayView | BMKPrismOverlayView.h | 棱柱视图 |
| BMKTraceOverlay | BMKTraceOverlay.h | 路书轨迹 |
| BMKTraceOverlayView | BMKTraceOverlayView.h | 路书轨迹视图 |
| BMK3DTraceOverlay | BMK3DTraceOverlay.h | 3D 轨迹 |
| BMK3DTraceOverlayView | BMK3DTraceOverlayView.h | 3D 轨迹视图 |
| BMKMapTrackAnimation | BMKMapAnimation.h | 轨迹动画 |
| BMKCommonDef | BMKCommonDef.h | 枚举定义 |

详见 [annotations.md](annotations.md)、[overlays.md](overlays.md)。

## 检索

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKSuggestionSearch | BMKSuggestionSearch.h | 建议检索 |
| BMKGeoCodeSearch | BMKGeoCodeSearch.h | 地理编码 |
| BMKPOISearch | BMKPOISearch.h | POI |
| BMKBusLineSearch | BMKBusLineSearch.h | 公交线路 |
| BMKRouteSearch | BMKRouteSearch.h | 路线检索（算路见路线规划） |

## 路线规划

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKRouteSearch | BMKRouteSearch.h | 路线检索 |
| BMKDrivingRoutePlanOption | BMKRouteSearchOption.h | 驾车 |
| BMKWalkingRoutePlanOption | BMKRouteSearchOption.h | 步行 |
| BMKRidingRoutePlanOption | BMKRouteSearchOption.h | 骑行 |
| BMKTransitRoutePlanOption | BMKRouteSearchOption.h | 公交 |
| BMKPlanNode | BMKTypes.h | 路线节点（pt、name、cityName、cityID） |
| BMKDrivingRouteResult / BMKWalkingRouteResult 等 | BMKRouteSearchResult.h | 算路结果 |
| BMKDrivingStep / BMKWalkingStep 等 | BMKRouteSearchType.h | 路线步骤类型 |

## 步骑行导航（BaiduWalkNaviKit）

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKWalkNavigationManager | BMKWalkNavigationManager.h | 步行导航管理，单例；destroy、initNaviEngine、routePlanWithParams、startWalkNaviWithParentController、getBackgroundNavigationView |
| BMKCycleNavigationManager | BMKCycleNavigationManager.h | 骑行导航管理，单例；destroy、initNaviEngine、routePlanWithParams、naviCalcRoute:、startCycleNaviWithParentController、getBackgroundNavigationView |
| BMKWalkNaviLaunchParam | BMKWalkNaviLaunchParam.h | 步行算路参数（startNode/endNode，BMKWalkNaviRouteNodeInfo） |
| BMKCycleNaviLaunchParam | BMKCycleNaviLaunchParam.h | 骑行算路参数（startNode/endNode） |
| BMKWalkNaviRouteNodeInfo | BMKWalkNaviRouteNodeInfo.h | 步行起/终点节点（type BMKWalkNavigationRouteNodeLocation 等） |
| BMKCycleNaviRouteNodeInfo | BMKCycleNaviRouteNodeInfo.h | 骑行起/终点节点 |
| BMKWalkCycleNavigationOptions | BMKWalkCycleNavigationOptions.h | 初始化选项（displayOption 等） |
| BMKWalkCycleNavigationDisplayOption | BMKWalkCycleNavigationDisplayOption.h | 展示选项 |
| BMKWalkCycleSampleGuideInfo | BMKWalkCycleSampleGuideInfo.h | 诱导信息（SampleGuide） |
| BMKMultiNaviView | BMKMultiNaviView.h | 多实例导航地图 View（getNaviMapView） |

后台投屏类（BMKBackgroundMapView、BMKBackgroundNavigationView、BMKBackgroundRoadNetView）见下「后台与导航」。

详见 [navi.md](navi.md)。

## 热力图

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKHeatMap | BMKHeatMap.h | 热力图 |
| BMKHexagonHeatMap | BMKHexagonHeatMap.h | 六边形热力图 |

## 后台与导航

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKBackgroundMapView | BMKBackgroundMapView.h | 后台投屏容器（mapview + roadNetView + navigationView） |
| BMKBackgroundNavigationView | BMKBackgroundNavigationView.h | 导航层：路线、车标、罗盘、起终点；步骑行由 Manager.getBackgroundNavigationView 获取 |
| BMKBackgroundRoadNetView | BMKBackgroundRoadNetView.h | 路网层：路网、路况、路名；从 backgroundMapView.roadNetView 获取 |
| BMKNavigation | BMKNavigation.h | 调起百度地图 |
| BMKNaviPara | BMKNaviPara.h | 导航参数 |

## 坐标与结构体

| 类型 | 说明 |
|------|------|
| CLLocationCoordinate2D | 经纬度（BD09） |
| BMKMapRect | 直角地理坐标矩形 |
| BMKMapPoint | 直角地理坐标点 |
| BMKCoordinateRegion | 经纬度区域 |
| BMKCoordinateBounds | 经纬度边界 |

## 工具

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKGeometry | BMKGeometry.h | 坐标转换、几何计算 |
| BMKInterpolator | BMKInterpolator.h | 动画插值器 |
| BMKCommonDef | BMKCommonDef.h | 枚举定义 |

详见 [utils.md](utils.md)。


path: references/ui-standards.md
content: # 地图 UI 标准

**边界**：检索、路线、选点、弹窗、视野、Logo 等 UI 规范；开发者无特殊要求时按此实现，具体功能见各功能文档。

## 基础规范

| 规范 | 标准 |
|------|------|
| 触控区域 | 可点击元素最小 44×44pt，保证单指易点 |
| 安全区域 | 尊重 Safe Area，刘海屏顶部预留约 44pt |
| 栅格 | 间距、尺寸优先用 8 的倍数（8、16、24、32pt），便于多倍屏 |
| 页边距 | 左右 16～24pt，避开屏幕边缘 |
| 字体 | 优先系统字体；标题 17～19pt、正文 15～16pt、辅助 12～14pt |
| 圆角 | 面板 12pt、输入框 8pt、胶囊按钮 height/2 |
| 一致性 | 相似功能元素样式一致；重要内容放上半屏偏左 |

---

## 检索面板

| 属性 | 标准值 |
|------|--------|
| 背景 | 浅灰 (0.96, 0.97, 0.98)，起终点输入框内为白色 |
| 圆角 | 12pt |
| 阴影 | 轻微阴影 |
| 边距 | 距屏幕左右 16pt |
| 布局顺序 | 起终点检索框在上，算路方式在下 |

---

## 地点检索（Sug）

| 属性 | 标准值 |
|------|--------|
| 防抖 | 输入延迟约 0.25s 再发起检索 |
| 关键字长度 | ≥2 再发起检索 |
| 主标题 | 优先 key，否则 address |
| 副标题 | address、城市+区、tag |
| 背景 | 白色、圆角 12pt |
| 分隔线 | 左侧留空约 50pt |
| 单元格 | 15pt 字体、深灰文字 |
| 布局对齐 | 检索框与结果列表同水平边距（16pt）；左侧图标区约 50pt，文字起始对齐 |
| 行前图标 | 每行结果前可加地点 pin 图标（如 SF Symbol mappin.circle.fill），居中于 50pt 区域 |
| 性能 | 延后 `becomeFirstResponder` 至下一 RunLoop；避免在 viewDidAppear 中自定义 searchBar 内部结构 |
| 提示条文案 | 宜简短，如「以下结果超过200米，请确认」，避免冗长占空间 |
| 键盘避让 | 键盘弹出时列表**必须**做避让（如监听 UIKeyboardWillShow/Hide，设置 tableView.contentInset.bottom = 键盘高度），避免结果被键盘遮挡 |
| 列表文案 | 副标题单行截断；出入口标签可去掉冗余「选择」等字，仅保留名称与比例等关键信息；子节点（出入口）**优先显示 showName（简称）**，无则用 name，见 [search.md](search.md) |

**Sug 与无经纬度首条**：Sug 第一条可能为无经纬度的关键词联想（如输入「肯」出「肯德基」），不对应确切 POI。**不过滤**该条；用户点击时将其作为**关键词填入检索框并继续 Sug 检索**，而非选点。无结果时可用 POI 检索继续搜。详见 [search.md](search.md)。

---

## 路线规划

### 起终点输入框

| 属性 | 标准值 |
|------|--------|
| 起点标识 | 左侧浅蓝圆点 (0.35, 0.65, 0.95) 或绿色 (0.2, 0.8, 0.4) |
| 终点标识 | 左侧橙红圆点 (0.95, 0.3, 0.25) |
| 占位符 | 「输入起点」「输入终点」 |
| 样式 | 无边框、白色背景、圆角 8pt |
| 字体 | 15pt 系统字体 |
| 位置 | 检索面板顶部 |

### 算路方式选择器

| 属性 | 标准值 |
|------|--------|
| 形式 | UIScrollView + 胶囊按钮（水平滚动） |
| 选项 | 驾车 \| 步行 \| 骑行（可扩展公交、新能源等） |
| 选中样式 | 科技蓝背景 (0, 0.55, 0.95)、白字 |
| 未选样式 | 白底、深灰字 (0.3, 0.3, 0.35) |
| 高度 | 36pt，圆角 = height/2（胶囊形） |
| 位置 | 检索框下边 |

### 路线规划布局

- **检索面板**：起终点输入在上，算路方式在下；可隐藏主标题、整体上移以扩大地图可视区
- **底部栏**：路线详情、模拟行驶按钮置于屏幕底部；总里程时间卡片在按钮上方，有路线时显示
- **自动算路**：起终点都有值后直接算路；切换算路方式后直接算路；重选起终点后按当前算路方式算路；算路方式默认驾车
- **模拟导航**：点击「模拟行驶」可跳转至独立模拟导航页，全屏展示路线与小车动画，提供「返回」「停止模拟」操作
- **可选**：详情按钮、骑行类型切换（普通/电动车）

### 公交多方案

TableView 展示每条方案的时长、距离、换乘概要；选中后绘制路线并适配视野。

---

## 配色（地图科技感）

路线规划相关采用蓝色系，适配地图场景与科技感：

| 用途 | RGB（0～1） | 说明 |
|------|-------------|------|
| 路线详情按钮 | 白底 + 浅蓝描边 (0.4, 0.7, 1.0) + 科技蓝字；无路线时禁用 | 描边样式 |
| 模拟行驶（可用） | (0, 0.55, 0.95) | 科技蓝 |
| 模拟行驶（禁用） | (0.9, 0.93, 0.96) | 浅蓝灰 |
| 停止模拟 | (0.95, 0.35, 0.2) | 橙红 |
| 算路方式选中项 | (0, 0.55, 0.95) | 科技蓝 |
| 算路方式未选 | 白底 + 深灰字 (0.3, 0.3, 0.35) | — |

起终点圆点：起点浅蓝 (0.35, 0.65, 0.95) 或绿 (0.2, 0.8, 0.4)，终点橙红 (0.95, 0.3, 0.25)。

---

## 按钮

| 按钮 | 样式 |
|------|------|
| 路线详情 | 白底、浅蓝描边、蓝色文字；胶囊圆角；有路线时可用，点击跳转路线详情页 |
| 模拟行驶（可用） | 科技蓝背景、白字；胶囊圆角；点击跳转模拟导航页 |
| 模拟行驶（禁用） | 浅蓝灰背景、半透明白字 |
| 停止模拟 | 橙红背景、白字（在模拟导航页） |
| 字体 | 16pt Medium |

## 总里程时间卡片

| 属性 | 标准值 |
|------|--------|
| 位置 | 底部栏内、按钮上方 |
| 背景 | 白色、圆角 12pt、轻微阴影 |
| 时长 | 大号粗体 20pt，如「22小时54分」 |
| 里程 | 13pt 浅灰，如「2185公里」 |
| 路线类型 | 12pt 浅灰，如「驾车」「步行」「骑行」 |
| 显示时机 | 有路线时显示 |

---

## 地图选点

| 属性 | 标准值 |
|------|--------|
| 布局 | 地图占上半部分，底部 TableView 约 160pt |
| 列表行高 | 约 75pt |
| 第一行 | 逆地理 address（可加【】标题） |
| 后续行 | poiList 中的 POI（name、address、pt） |
| 选点动画 | regionWillChange 标注跳起，regionDidChange 落下 |

---

## 隐私协议弹窗

| 属性 | 标准值 |
|------|--------|
| 时机 | 首次使用前弹窗，用户同意后调用 `setAgreePrivacy:YES` |
| 记录 | NSUserDefaults 避免重复弹窗 |
| 未同意 | 检索对象延迟创建；使用检索前提示用户同意 |
| 隐私政策 | 弹窗内可跳转，地址见 project-config |

---

## 起终点与覆盖物

| 属性 | 标准值 |
|------|--------|
| 起终点图标 | 添加顺序：路线→起终点→小车；**须优先使用** [assets](assets.md) 的 **icon_start、icon_end**，无纹理时再自绘/纯色；scaleX/scaleY 根据实际图片尺寸与地图 zoomLevel 做视觉适配 |
| 路线纹理 | **须优先使用** BMKPolylineView.textureImage（图片宽高 2 的 n 次幂）或 BMKMultiTexturePolylineView+路况纹理；无纹理时再用 strokeColor。线宽 8pt。 |
| 路线小车纹理 | **必须优先使用**技能 [assets](assets.md) 提供的纹理（icon_car / car_triangle / track_car）；无纹理时才用颜色或自绘 |
| 算路页 | 不添加 carMarker，polyline.animation = nil，静态展示 |
| 路线线宽 | 8pt |
| 路名字体 | 22pt，黑字白边；路线路名**使用 BMKTextPathMarker** 沿路径绘制，见 [overlays.md](overlays.md) |
| 拐角 | 圆角 |

---

## 路线视野适配（必须考虑）

有路线绘制时**必须**做视野适配。**仅用 fitVisibleMapRect 的 edgePadding**，与 mapPadding 分开（mapPadding 管 Logo/指南针）。

| 场景 | edgePadding |
|------|-------------|
| 路线全屏 | 上下约 80、左右约 40 |
| 标注可见 | 左右约 50、上下约 40 |
| 路线规划 | 顶部留检索面板+50+marker 尺寸，底部留底部栏+20+marker 尺寸，左右约 50+marker 尺寸 |
| marker 预留 | 起终点图标约 44pt，fitVisibleMapRect 的 edgePadding 需预留，避免被 UI 遮挡 |

---

## 地图 Logo、指南针与 mapPadding（Logo 不能被遮挡）

**mapPadding** 与 **fitVisibleMapRect edgePadding** 解决不同问题，勿混用：

| 用途 | 方法 | 说明 |
|------|------|------|
| 指南针、Logo 遮挡 | `setMapPadding` | 影响指南针、Logo、比例尺位置，使其避开 UI 区域 |
| 路线视野适配 | `fitVisibleMapRect:edgePadding:` | 控制路线、起终点在可见区域内的适配，含 UI 边距和 marker 尺寸 |

百度地图 Logo **不可移除、不允许遮挡**，有地图且存在浮动栏/底部栏时**必须**通过 setMapPadding 预留边界。当有浮动栏时，用 `setMapPadding` 预留边界；**底部预留尽量小**（如 barH + 4），使 Logo 更靠下、避免喧宾夺主：

```objc
// 顶部预留检索面板，底部预留尽量小使 Logo 更靠下
[_mapView setMapPadding:UIEdgeInsetsMake(topPad, 0, barH + 4, 0)];
```

---

## Logo 与比例尺布局

**默认问题**：比例尺与 Logo 同在左下角时会重叠，需手动设置 `mapScaleBarPosition` 使比例尺在 Logo 上方。

**SDK 内部**（updateLogoPosition）：Logo 在内容区 `(mapW, mapH)` 内布局；LeftBottom 时全面屏 `logoOrigin = (mapW*0.05, mapH - logoH - mapH*0.03)`，非全面屏 `(0, mapH - logoH)`；最终 frame 加 `mapPadding.left/top`。

**推荐实现**：`logoPosition = BMKLogoPositionLeftBottom`，在 `mapViewDidFinishLoading` 与 `viewDidLayoutSubviews` 中调用 `layoutScaleBarAboveLogo`：

```objc
- (void)layoutScaleBarAboveLogo {
    if (!self.mapView) return;
    UIEdgeInsets pad = self.mapView.mapPadding;
    CGFloat mapW = CGRectGetWidth(self.mapView.bounds) - pad.left - pad.right;
    CGFloat mapH = CGRectGetHeight(self.mapView.bounds) - pad.top - pad.bottom;
    CGFloat logoX = mapW * 0.05;   // 与 SDK LeftBottom 全面屏一致
    CGFloat logoH = 28;
    CGFloat logoBottomMargin = mapH * 0.03;
    CGFloat logoTop = mapH - logoH - logoBottomMargin;
    CGSize scaleSize = self.mapView.mapScaleBarSize;
    if (scaleSize.height <= 0) scaleSize.height = 22;
    CGFloat gap = 6;
    CGFloat y = logoTop - scaleSize.height - gap;
    if (y < 8) y = 8;
    CGFloat x = pad.left + logoX;  // 比例尺左边与 Logo 左边对齐
    self.mapView.mapScaleBarPosition = CGPointMake(x, y);
}
```

---

## 手势与 ScrollView

地图嵌入横向 ScrollView（如 Tab 切换）时，多手势同时识别；ScrollView 关闭 delaysContentTouches 便于响应。

---

## 3D 与动画

| 场景 | 标准值 |
|------|--------|
| 3D 模型展示 | zoomLevel 18、overlooking -30、关闭 3D 楼块 |
| 算路页 | 路线和小车无动画，静态展示；polyline.animation = nil，不添加 carMarker |
| 模拟行驶页 | 路线纹理已走过置灰、未走过原色；小车沿轨迹动画 |

---

## 按参考 UI 图严格写布局（通用提示词）

有参考 UI 图时，可用以下要求约束大模型，避免实现过于简单或不美观：

1. **像素级对齐**：边距、圆角、字号、行高须与图中一致或按比例换算（有设计稿标注时写出换算规则）。
2. **视觉层级**：区分主标题 / 副标题 / 辅助文字的字重、字号、颜色；按钮、卡片、分割线要有明确层级和对比。
3. **禁止简化**：图中的阴影、圆角、描边、图标、留白都要体现，不用「简单列表」「普通按钮」敷衍。
4. **配色与风格**：从图中提取主色、辅色、背景色、边框色并用常量命名；整页风格统一（如科技感 / 简约）。
5. **输出要求**：先列出从图中读出的关键尺寸和样式（边距、圆角、字号、颜色），再写代码；代码中禁止魔法数字，须用有意义的常量或设计 token。

**简短版提示词**（可放入系统提示或规则）：

> 按参考 UI 图严格实现：边距/圆角/字号/颜色与图一致；区分标题与正文层级；保留阴影、描边、图标等细节；禁止简化或「差不多就行」；尺寸和颜色用命名常量，不写魔法数字。

**避免的说法**：❌「参考一下这个图」❌「风格类似即可」❌「做一个简单的 XXX 页面」  
**建议的说法**：✅「严格按照附图实现，边距、圆角、字号、颜色与图一致」✅「先列出从图中提取的尺寸和配色，再写布局代码」

---

## 使用说明

- 开发者有自定义 UI 需求时，可偏离此标准
- 本技能生成代码时，默认采用上述标准，保证界面专业统一


path: references/cocoapods.md
content: # CocoaPods 集成

**版本**：不写版本号即使用最新；写版本号则锁定。API 以本地头文件为准，类/方法不存在时提示更新 Pod，见 [SKILL.md](../SKILL.md) 规则 5。

## 安装 CocoaPods（未安装时）

```bash
gem sources -l
gem sources --remove https://rubygems.org/
gem sources -a https://gems.ruby-china.com
sudo gem update --system
sudo gem install -n /usr/local/bin cocoapods  # macOS > 10.11
pod setup
```

## Podfile 模板

**仅定位**（BMKLocationKit，无地图）：
```ruby
platform :ios, '9.0'
target 'YourProjectTarget' do
  pod 'BMKLocationKit', '2.1.3'
end
```

**基础地图**（BaiduMapKit，不写版本号即使用最新）：
```ruby
platform :ios, '10.0'
target 'YourProjectTarget' do
    pod 'BaiduMapKit'
    # pod 'BaiduMapKit/Map'
    # pod 'BaiduMapKit/Search'
    # pod 'BaiduMapKit/Utils'
end
```

**步骑行导航**（BaiduWalkNaviKit，含基础地图，步行/骑行实时导航）：
```ruby
platform :ios, '10.0'
target 'YourProjectTarget' do
    pod 'BaiduWalkNaviKit'
end
```
步骑行导航依赖、配置与示例见 [navi.md](navi.md)。

## 常用命令

```bash
pod install          # 安装后用 .xcworkspace 打开
pod repo update
pod update
```

## pod search 找不到类库

```bash
pod setup
rm ~/Library/Caches/CocoaPods/search_index.json
pod search BaiduMapKit   # 或 pod search BMKLocationKit
```

---

## 后续配置

Info.plist、隐私协议弹窗见 [project-config.md](project-config.md)，图片资源见 [assets.md](assets.md)。

**构建报错**：若出现 `Sandbox: bash deny file-write-create .../Pods/resources-to-copy-xxx.txt`，需关闭 User Script Sandboxing，见 [project-config.md](project-config.md) 的「CocoaPods 构建沙盒」小节。


path: references/project-config.md
content: # 工程配置

**边界**：Info.plist、隐私弹窗、Launch Screen、CocoaPods 沙盒等百度 SDK 工程配置；Pod 集成见 [cocoapods.md](cocoapods.md)。

**Agent 注意**：集成地图/定位 SDK 时，必须检查或配置 Launch Screen（见下「窗口初始化/Launch Screen」），避免运行后 App 非全屏、黑边；并主动提示开发者配置 AK 与 Bundle Identifier（与百度控制台一致）。

## Info.plist 必配项

**CFBundleExecutable**（使用自定义 Info.plist 且 `GENERATE_INFOPLIST_FILE = NO` 时必配）：指定主可执行文件名，未配置会导致真机安装失败，报错「missing or invalid CFBundleExecutable」「无法安装」「请稍后再试」（Code 3002 / MIInstallerErrorDomain 11）。须在 plist 中显式添加：

```xml
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
```

编译时 Xcode 会将 `$(EXECUTABLE_NAME)` 展开为 target 的主可执行文件名（通常与 Product Name 一致）。

**CFBundleDisplayName**：SDK 启动时校验，未配置会报错「启动引擎失败: info.plist 中必须配置 Bundle display name」。

```xml
<key>CFBundleDisplayName</key>
<string>你的应用名称</string>
```

**定位权限**（使用定位时）：
```xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要获取您的位置以展示地图</string>
```

**调起百度地图客户端**（驾车/步行/骑行调起百度地图 App 时）：
1. 必须在 Info.plist 中配置 **LSApplicationQueriesSchemes**（baidumap），否则无法调起百度地图 App。
2. **指定返回自定义 scheme**：`appScheme` 按 **`scheme://host`** 格式填写（如 `yourapp://mapsdk.yourapp.com`）。scheme 名（`://` 前部分）须与 Info.plist 中 **CFBundleURLSchemes** 注册的一致，这样用户在百度地图内点击「返回」时才能通过该 URL 打开本 App。

LSApplicationQueriesSchemes：
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>baidumap</string>
</array>
```

返回本 App 的 URL Scheme 注册（CFBundleURLSchemes 填 appScheme 的 scheme 部分，与格式 scheme://host 中的 scheme 一致）：
```xml
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLName</key>
        <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>foodsearchdemo</string>
        </array>
    </dict>
</array>
```
示例：若 `para.appScheme = @"foodsearchdemo://mapsdk.foodsearchdemo.com"`，则此处填 `foodsearchdemo`。

**步行 AR 导航**（使用 BaiduWalkNaviKit 且进入 AR 导航时）：必须配置相机用途说明，否则访问摄像头会**直接崩溃**。
```xml
<key>NSCameraUsageDescription</key>
<string>步行AR导航需要使用摄像头识别周围环境，为您提供实景导航指引</string>
```

## 隐私协议弹窗（必做）

**首次使用前必须弹窗提示用户阅读并同意隐私政策**，再调用 `[BMKMapManager setAgreePrivacy:YES]`。未同意时调用 `[BMKMapManager setAgreePrivacy:NO]`。

**注意**：`setAgreePrivacy:` 是 **BMKMapManager 的类方法**，必须写 `[BMKMapManager setAgreePrivacy:YES]`，**勿写** `[[BMKMapManager sharedInstance] setAgreePrivacy:YES]`（会报 "Instance method '-setAgreePrivacy:' not found"）。

**隐私政策地址**：https://lbsyun.baidu.com/index.php?title=openprivacy（弹窗内需可点击跳转）。

UI 标准见 [ui-standards.md](ui-standards.md)。**不同意时**：`setAgreePrivacy:NO`，BMKSearchBase 及其子类会返回 nil；需延迟创建检索对象，仅在用户同意后创建；未同意时使用检索前提示用户去同意。

## CocoaPods 构建沙盒（Xcode 15+）

CocoaPods 的 Copy Pods Resources 脚本需在 `Pods` 目录创建临时文件（如 `resources-to-copy-${TARGETNAME}.txt`）。Xcode 15 起默认开启 **User Script Sandboxing**，会阻止该写入，导致构建报错：

```
Sandbox: bash deny(1) file-write-create .../Pods/resources-to-copy-xxx.txt
```

**解决**：在 target 的 Build Settings 中设置 `ENABLE_USER_SCRIPT_SANDBOXING = NO`。

- **Xcode 图形界面**：选中 target → Build Settings → 搜索 "User Script Sandboxing" → 设为 **No**
- **project.pbxproj**：在 target 的 XCBuildConfiguration（Debug/Release）的 buildSettings 中添加：
  ```
  ENABLE_USER_SCRIPT_SANDBOXING = NO;
  ```

## 窗口初始化/Launch Screen

**现象**：地图未铺满屏幕、上下或左右出现黑边，地图只显示在中间一块区域。

**原因**：未配置 Launch Screen 时，系统会按「未声明支持当前设备屏幕」处理，窗口或根视图的尺寸/安全区域可能异常，导致 `view.bounds` 不是全屏，地图即使用 `view.bounds` 设 frame 也会出现黑边。

**必配**：工程需有 Launch Screen（LaunchScreen.storyboard 或同类），并在 Info.plist 中配置：

```xml
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
```

LaunchScreen.storyboard 需设置 `launchScreen="YES"`、`useSafeAreas="YES"`，支持各尺寸 iPhone（含刘海屏）。内容可为白底 + 应用名等静态界面。

**地图不全屏排查顺序**（Agent 必须遵守）：
1. **先检查 Launch Screen**：是否有 LaunchScreen.storyboard（或 Launch Image）、Info.plist 是否含 `UILaunchStoryboardName`；缺则补上并加入 target Resources。
2. **再检查布局**：地图视图的 frame 是否在 `viewDidLayoutSubviews` 中设为 `self.view.bounds`（避免在 viewDidLoad/首次创建时 bounds 未稳定导致尺寸错误）。


path: references/route.md
content: # 路线规划

**边界**：算路与画线（**BMKRouteSearch**，BaiduMapKit）。步骑行实时导航为另一服务，见 [reference.md](reference.md) 选型与 [navi.md](navi.md)。

## 多场景路线类型

路线规划支持多种场景，UI 上可用分段控件或图标切换（参考百度地图 App）：

| 场景 | Option | 方法 | 结果类 | 路名/说明来源 |
|------|--------|------|--------|----------|
| 驾车 | BMKDrivingRoutePlanOption | drivingSearch: | BMKDrivingRouteResult | BMKDrivingStep.roadName |
| 步行 | BMKWalkingRoutePlanOption | walkingSearch: | BMKWalkingRouteResult | BMKWalkingStep.instruction |
| 骑行 | BMKRidingRoutePlanOption | ridingSearch: | BMKRidingRouteResult | BMKRidingStep.instruction |
| 公交 | BMKTransitRoutePlanOption | transitSearch: | BMKTransitRouteResult | BMKTransitStep.instruction、vehicleInfo |

**UI**：见 [ui-standards.md](ui-standards.md)。

## 核心类

| 类 | 头文件 | 说明 |
|----|--------|------|
| BMKRouteSearch | BMKRouteSearch.h | 路线检索，delegate 为 BMKRouteSearchDelegate |
| BMKPlanNode | BMKTypes.h | 路线节点（pt、name、cityName、cityID、floor、building、uid） |
| BMKDrivingRoutePlanOption | BMKRouteSearchOption.h | 驾车 |
| BMKWalkingRoutePlanOption | BMKRouteSearchOption.h | 步行 |
| BMKRidingRoutePlanOption | BMKRouteSearchOption.h | 骑行 |
| BMKTransitRoutePlanOption | BMKRouteSearch.h | 公交（市内） |
| BMKMassTransitRoutePlanOption | BMKRouteSearch.h | 跨城公交 |
| BMKIndoorRoutePlanOption | BMKRouteSearch.h | 室内 |
| BMKIntegralRoutePlanOption | BMKRouteSearch.h | 一体化路线 |
| BMKBusRoutePlanOption | BMKRouteSearch.h | 公交路线（市内+跨城，另一套接口） |

**BMKRouteSearch 方法**：`drivingSearch:`、`walkingSearch:`、`ridingSearch:`、`transitSearch:`、`massTransitSearch:`、`indoorRoutePlanSearch:`、`integralRoutePlanSearch:`、`busRoutePlanSearch:`。均为异步，结果在对应 Delegate 回调中返回。

**BMKRouteSearchDelegate 回调**：`onGetDrivingRouteResult:result:errorCode:`、`onGetWalkingRouteResult:result:errorCode:`、`onGetRidingRouteResult:result:errorCode:`、`onGetTransitRouteResult:result:errorCode:`、`onGetMassTransitRouteResult:result:errorCode:`、`onGetIndoorRouteResult:result:errorCode:`、`onGetIntegralRouteResult:result:errorCode:`、`onGetBusRouteResult:result:errorCode:`。先判断 `errorCode == BMK_SEARCH_NO_ERROR` 再使用 result。

## BMKPlanNode（路线节点）

路线节点可通过**经纬度 pt** 或 **地名 name + 城市** 指定；cityName 与 cityID 同时指定时 **cityID 优先**。

| 属性 | 类型 | 说明 |
|------|------|------|
| name | NSString | 地名（与 cityName 组合使用） |
| pt | CLLocationCoordinate2D | 经纬度，与 name 二选一或同时用于提高精度 |
| cityName | NSString | 节点所在城市 |
| cityID | NSInteger | 城市 ID，与 cityName 同设时优先 |
| floor | NSString | 楼层（室内等场景） |
| building | NSString | 建筑物（室内等场景） |
| uid | NSString |  POI 唯一标识，可选 |

驾车示例：`start.name = @"天安门"`，`start.cityName = @"北京市"`。

## 路线 Option 参数一览

**公共（BMKBaseRoutePlanOption）**：`from`、`to`（BMKPlanNode，起/终点，必填）。

| 类型 | Option 独有参数 | 说明 |
|------|------------------|------|
| 驾车 | wayPointsArray（BMKPlanNode 数组）、**drivingPolicy**、**drivingRequestTrafficType** | 途经点；策略与路况见下 |
| 步行 | 无 | 仅 from / to |
| 骑行 | **ridingType**、**roadPrefer**、wayPointsArray | 普通/电动车；道路偏好；途经点 |
| 公交（市内） | **city**（NSString）、**transitPolicy** | 城市必填；时间优先/换乘优先等 |
| 跨城公交 | **pageIndex**、**pageCapacity**、**incityPolicy**、**intercityPolicy**、**intercityTransPolicy**、**languageType** | 分页与市内/跨城策略 |

**驾车策略 drivingPolicy**（默认 BMK_DRIVING_TIME_FIRST）：如 BMK_DRIVING_BLK_FIRST（避免堵车）、BMK_DRIVING_TIME_FIRST（时间优先）、BMK_DRIVING_DIS_FIRST（距离优先）、BMK_DRIVING_FEE_FIRST（费用优先）等，详见 BMKRouteSearchType.h。

**路况 drivingRequestTrafficType**：`BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE`（默认，无路况）、`BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE`（带路况）。带路况时 Step 的 `traffics` 有效。

**公交策略 transitPolicy**：如 BMK_TRANSIT_TIME_FIRST（时间优先）、BMK_TRANSIT_TRANSFER_FIRST（换乘优先）、BMK_TRANSIT_WALK_FIRST（步行少）等。

**骑行 ridingType**：`BMK_RIDING_TYPE_NORMAL`（普通）、`BMK_RIDING_TYPE_ELECTRIC`（电动车）。**roadPrefer**：道路偏好枚举，见 BMKRouteSearchType.h。

## 驾车路线

| 类 | 说明 |
|----|------|
| BMKDrivingRouteResult | routes（BMKDrivingRouteLine 数组） |
| BMKDrivingRouteLine | steps、duration（BMKTime）、distance、lightNum 等 |
| BMKDrivingStep | points、pointsCount、roadName、instruction、**traffics**、direction、entrace/exit、hasTrafficsInfo 等 |

**路况**：`BMKDrivingStep.traffics` 为 NSArray&lt;NSNumber *&gt;，0=无数据，1=畅通，2=缓行，3=拥堵，4=严重拥堵。需带路况时设置 `drivingRequestTrafficType = BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE`。textureImages 须按顺序提供 5 张纹理（含 traffic_texture_severe_congestion），见 [assets.md](assets.md)。

**路线线宽**：BMKPolylineView / BMKMultiTexturePolylineView 的 **lineWidth 标准 8pt**，见 [ui-standards.md](ui-standards.md)。

**回调**：`onGetDrivingRouteResult:result:errorCode:`

## 坐标与路况提取

**驾车路况解析**：请求时设置 `drivingRequestTrafficType = BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE`。坐标按 step 顺序拷贝到总数组；**路况 drawIndexs 按各 step 的 traffics 直接拼接即可**，无需在 step 之间补 0，也无需按 `pointsCount - 1` 补齐。traffics 中 0=无数据、1=畅通、2=缓行、3=拥堵、4=严重拥堵，与 [assets](assets.md) 中 traffic_texture_* 顺序一致。若 `drawIndexs.count < pointCount - 1` 可回退为单折线 BMKPolyline。

```objc
BMKDrivingRouteLine *line = result.routes.firstObject;
NSUInteger pointCount = (NSUInteger)line.totalPointsCount;
BMKMapPoint *points = malloc(pointCount * sizeof(BMKMapPoint));
NSMutableArray<NSNumber *> *drawIndexs = [NSMutableArray array];
NSUInteger j = 0;
for (BMKDrivingStep *step in line.steps) {
    for (NSUInteger i = 0; i < (NSUInteger)step.pointsCount; i++) {
        points[j].x = step.points[i].x;
        points[j].y = step.points[i].y;
        j++;
    }
    for (NSNumber *t in step.traffics) {
        [drawIndexs addObject:t];
    }
}
BMKMultiPolyline *polyline = [BMKMultiPolyline multiPolylineWithPoints:points count:pointCount drawIndexs:drawIndexs];
free(points);
```

## 单色路线（无路况）

步行/骑行/驾车/公交的 **BMKRouteLine**（及子类）均有 **totalPointsCount**，可直接取总点数，无需遍历 steps 累加。Step 均继承 BMKRouteStep，有 `points`、`pointsCount`，将各 step 的 points 依次拷贝到一块缓冲区即可：

```objc
NSUInteger pointCount = (NSUInteger)line.totalPointsCount;  // 直接取总点数
BMKMapPoint *points = malloc(pointCount * sizeof(BMKMapPoint));
NSUInteger j = 0;
for (BMKRouteStep *step in line.steps) {
    for (NSUInteger i = 0; i < step.pointsCount; i++) {
        points[j++] = step.points[i];
    }
}
BMKPolyline *polyline = [BMKPolyline polylineWithPoints:points count:pointCount];
free(points);
```

## 起终点标注

- 起点：`line.steps.firstObject.points[0]` 或 `BMKCoordinateForMapPoint(points[0])`
- 终点：`line.steps.lastObject.points[step.pointsCount-1]` 或 `points[pointCount-1]`
- 起终点**必须用 BMKIconMarker**（addOverlay）展示，不得用 BMKPointAnnotation/BMKPinAnnotationView，见 [overlays.md](overlays.md)、[SKILL.md](../SKILL.md)

## 路线路名绘制

- **路名**：`BMKDrivingStep.roadName` 可用 **BMKTextPathMarker** 沿该 step 的 `points`/`pointsCount` 绘制，文字随路径走向展示。创建 `[BMKTextPathMarker textPathMarkerWithPoints:step.points count:step.pointsCount]`，设置 `text = step.roadName`、`style`（BMKTextStyle，如 22pt 黑字白边），View 用 **BMKTextPathMarkerView** 的 `initWithMarker:`。详见 [overlays.md](overlays.md)「BMKTextPathMarker」、[ui-standards.md](ui-standards.md) 路名字体。

## 视野适配（mapViewFitPolyline，必须考虑）

绘制路线后**必须**做视野适配，使路线与起终点完整落在可视区内且不被 UI 遮挡；同时须保证 Logo 不被遮挡（用 setMapPadding，见 [ui-standards.md](ui-standards.md)）。BMKPolyline 遵循 BMKOverlay，可直接用 **boundingMapRect** 获取折线外包矩形，无需遍历点：

```objc
- (void)mapViewFitPolyline:(BMKPolyline *)polyline {
    if (polyline.pointCount < 2) return;
    BMKMapRect rect = polyline.boundingMapRect;
    [_mapView fitVisibleMapRect:rect edgePadding:UIEdgeInsetsMake(80, 40, 80, 40) withAnimated:YES];  // 标准见 ui-standards
}
```

## 公交多方案

`BMKTransitRouteResult.routes` 为多条方案数组；每条 BMKTransitRouteLine 含 steps（BMKTransitStep）。BMKTransitStep 有 **stepType**（BMK_BUSLINE/BMK_SUBWAY/BMK_WAKLING）、**vehicleInfo**（线路名、首末班等）、instruction、entrace/exit。UI 见 [ui-standards.md](ui-standards.md)。选中某条后绘制并 `mapViewFitPolyline` 适配视野。

**跨城公交**：使用 `massTransitSearch:` + BMKMassTransitRoutePlanOption（from/to 为 BMKPlanNode，起终点城市不支持 cityID，仅 name+cityName）；回调 `onGetMassTransitRouteResult:result:errorCode:`，结果含多种跨城方式（火车、飞机、大巴等）。

**公交线路详情**：BMKBusLineSearch（见 [search.md](search.md)）按线路 UID 查站点与走向，与路线规划为不同能力。

## 骑行类型与道路偏好

- **ridingType**：`BMK_RIDING_TYPE_NORMAL`（普通）、`BMK_RIDING_TYPE_ELECTRIC`（电动车）。
- **roadPrefer**：道路偏好（如优先非机动车道等），见 BMKRouteSearchType.h 中 BMKRidingRoadPrefer。
- 骑行支持 **wayPointsArray**（途经点）。

## 时长与距离格式化

```objc
// duration：BMKTime 含 hours、minutes
NSString *time;
if (routeLine.duration.hours > 0 && routeLine.duration.minutes > 0)
    time = [NSString stringWithFormat:@"%d小时%d分", routeLine.duration.hours, routeLine.duration.minutes];
else if (routeLine.duration.hours > 0)
    time = [NSString stringWithFormat:@"%d小时", routeLine.duration.hours];
else
    time = [NSString stringWithFormat:@"%d分钟", routeLine.duration.minutes];

// distance：米/公里
NSString *distance = routeLine.distance < 100
    ? [NSString stringWithFormat:@"%d米", routeLine.distance]
    : [NSString stringWithFormat:@"%.1f公里", routeLine.distance / 1000.0];
```

## 详情页（Step 列表）

- 从 `line.steps` 构建 DetailModel 数组：`instruction`、`cellHeight`、`stepType`（公交用 BMKTransitStepType）
- 公交：`step.vehicleInfo.title` 作为线路标签，`step.stepType >= BMK_WAKLING` 为步行段可跳过
- 步行/骑行：`step.instruction` 直接展示

---

## 按需方案

| 需求 | 能力组合 | 说明 |
|------|----------|------|
| 驾车路线（无路况） | BMKRouteSearch + BMKPolyline | 合并 steps 为单折线 |
| 驾车路线（带路况） | BMKRouteSearch + BMKMultiPolyline + drawIndexs | drivingRequestTrafficType=PATH_AND_TRAFFICE，traffics→textureImages |
| 步行/骑行仅算路画线 | BMKRouteSearch + BMKPolyline | walkingSearch/ridingSearch；实时导航见上文「步骑行实时导航」 |
| 步骑行多路线选路+应用内导航 | BaiduWalkNaviKit + [navi.md](navi.md) | 多路线选路与导航生命周期见 navi.md |
| 多场景切换 UI | UISegmentedControl（驾车\|步行\|骑行） | 参考 ui-standards.md |
| 起终点选点 | BMKSuggestionSearch | [search.md](search.md) |
| 路线动画 | BMKMapTrackAnimation | [overlays.md](overlays.md) |


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)