├── .gitignore ├── Podfile ├── Podfile.lock ├── README.md ├── iOS_ClusterAnnotation_3D-swift ├── AnnotationClusterViewController.swift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ └── Icon-App-60x60@3x.png ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist └── Swift-Bridge-Header.h ├── iOS_ClusterAnnotation_3D.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── iOS_ClusterAnnotation_3D-swift.xcscheme │ ├── iOS_ClusterAnnotation_3D.xcscheme │ └── iOS_ClusterAnnotation_3DUITests.xcscheme ├── iOS_ClusterAnnotation_3D ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ └── Icon-App-60x60@3x.png ├── Base.lproj │ └── LaunchScreen.storyboard ├── ClusterAnnotation │ ├── Demo │ │ └── Controller │ │ │ ├── AnnotationClusterViewController.h │ │ │ ├── AnnotationClusterViewController.m │ │ │ ├── PoiDetailViewController.h │ │ │ └── PoiDetailViewController.m │ ├── Model │ │ ├── ClusterAnnotation.h │ │ ├── ClusterAnnotation.m │ │ ├── CoordinateQuadTree.h │ │ ├── CoordinateQuadTree.m │ │ ├── QuadTree.h │ │ └── QuadTree.m │ └── View │ │ ├── ClusterAnnotationView.h │ │ ├── ClusterAnnotationView.m │ │ ├── ClusterTableViewCell.h │ │ ├── ClusterTableViewCell.m │ │ ├── CustomCalloutView.h │ │ └── CustomCalloutView.m ├── Configuration │ └── APIKey.h ├── Info.plist └── main.m └── iOS_ClusterAnnotation_3DUITests ├── Info.plist └── iOS_ClusterAnnotation_3DUITests.m /.gitignore: -------------------------------------------------------------------------------- 1 | #xcode 2 | # 3 | #gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | .DS_Store 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | 62 | # 63 | *.xcworkspace 64 | 65 | Result/ 66 | output/ 67 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '8.0' 2 | 3 | target 'iOS_ClusterAnnotation_3D' do 4 | pod 'AMap3DMap' 5 | pod 'AMapSearch' 6 | end 7 | 8 | target 'iOS_ClusterAnnotation_3D-swift' do 9 | pod 'AMap3DMap' 10 | pod 'AMapSearch' 11 | end 12 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AMap3DMap (6.8.1): 3 | - AMapFoundation (~> 1.5) 4 | - AMapFoundation (1.5.6) 5 | - AMapSearch (6.6.0): 6 | - AMapFoundation (~> 1.4) 7 | 8 | DEPENDENCIES: 9 | - AMap3DMap 10 | - AMapSearch 11 | 12 | SPEC REPOS: 13 | https://github.com/cocoapods/specs.git: 14 | - AMap3DMap 15 | - AMapFoundation 16 | - AMapSearch 17 | 18 | SPEC CHECKSUMS: 19 | AMap3DMap: 9fa4ec6ab230bfbd3f0c0834f757fbd7038efe53 20 | AMapFoundation: 20fce2a12cd152e1092afdd04379cdac21932185 21 | AMapSearch: def5983c8ca1a6d7430970046dc814f6e337621d 22 | 23 | PODFILE CHECKSUM: 0843822cfb1a3e34433839e98e358c8bd272b4c6 24 | 25 | COCOAPODS: 1.6.1 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | iOS-cluster-marker 2 | ======================== 3 | 4 | MAMapKit 点聚合 5 | 6 | ### 前述 7 | 8 | - [高德官网申请Key](http://lbs.amap.com/dev/#/). 9 | - 阅读[开发指南](http://lbs.amap.com/api/ios-sdk/summary/). 10 | - 工程基于iOS 3D地图SDK实现 11 | - 关键词:点聚合 => h5入口:https://lbs.amap.com/api/javascript-api/guide/overlays/massmarker/ 12 | - 关键词:ios聚合 ios入口:https://lbs.amap.com/dev/demo/cluster-marker#iOS 13 | 14 | 15 | ### 核心类/接口 16 | | 类 | 接口 | 说明 | 版本 | 17 | | -----|:-----:|:-----:|:-----:| 18 | | AnnotationClusterViewController | - (void)searchPoiWithKeyword:(NSString *)keyword; | 根据关键字搜索poi点 | n/a | 19 | | CoordinateQuadTree | - (void)buildTreeWithPOIs:(NSArray *)pois; | 根据返回poi建树 | n/a | 20 | | AnnotationClusterViewController | - (void)addAnnotationsToMapView:(MAMapView *)mapView; | 把annotation添加到地图 | n/a | 21 | | AnnotationClusterViewController | - (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated; | 响应地图区域变化回调,刷新annotations | n/a | 22 | 23 | ### 使用教程 24 | 25 | - 调用ClusterAnnotation文件夹下的代码能够实现poi点聚合,使用步骤如下: 26 | - 初始化coordinateQuadTree。 27 | 28 | `Objective-C` 29 | ``` 30 | self.coordinateQuadTree = [[CoordinateQuadTree alloc] init]; 31 | ``` 32 | `Swift` 33 | ``` 34 | var coordinateQuadTree = CoordinateQuadTree() 35 | ``` 36 | 37 | - 获得poi数组pois后,创建coordinateQuadTree。 38 | * 项目Demo通过关键字搜索获得poi数组数据,具体见工程。此处从获得poi数组开始说明。 39 | * 创建四叉树coordinateQuadTree来建立poi的四叉树索引。 40 | * 创建过程较为费时,建议另开线程。创建四叉树完成后,计算当前mapView下需要显示的annotation。 41 | 42 | `Objective-C` 43 | ```objc 44 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 45 | /* 建立四叉树. */ 46 | [self.coordinateQuadTree buildTreeWithPOIs:respons.pois]; 47 | 48 | dispatch_async(dispatch_get_main_queue(), ^{ 49 | /* 计算当前mapView区域内需要显示的annotation. */ 50 | NSLog(@"First time calculate annotations."); 51 | [self addAnnotationsToMapView:self.mapView]; 52 | }); 53 | }); 54 | ``` 55 | 56 | `Swift` 57 | ``` 58 | DispatchQueue.global(qos: .default).async(execute: { [weak self] in 59 | 60 | self?.coordinateQuadTree.build(withPOIs: response.pois) 61 | self?.shouldRegionChangeReCalculate = true 62 | self?.addAnnotations(toMapView: (self?.mapView)!) 63 | }) 64 | ``` 65 | 66 | - 根据CoordinateQuadTree四叉树索引,计算当前zoomLevel下,mapView区域内的annotation。 67 | 68 | `Objective-C` 69 | ```objc 70 | - (void)addAnnotationsToMapView:(MAMapView *)mapView 71 | { 72 | /* 判断是否已建树. */ 73 | if (self.coordinateQuadTree.root == nil) 74 | { 75 | return; 76 | } 77 | /* 根据当前zoomLevel和zoomScale 进行annotation聚合. */ 78 | double zoomScale = self.mapView.bounds.size.width / self.mapView.visibleMapRect.size.width; 79 | /* 基于先前建立的四叉树索引,计算当前需要显示的annotations. */ 80 | NSArray *annotations = [self.coordinateQuadTree clusteredAnnotationsWithinMapRect:mapView.visibleMapRect 81 | withZoomScale:zoomScale 82 | andZoomLevel:mapView.zoomLevel]; 83 | 84 | /* 更新annotations. */ 85 | [self updateMapViewAnnotationsWithAnnotations:annotations]; 86 | } 87 | ``` 88 | `Swift` 89 | ``` 90 | func addAnnotations(toMapView mapView: MAMapView) { 91 | synchronized(lock: self) { [weak self] in 92 | 93 | guard (self?.coordinateQuadTree.root != nil) || self?.shouldRegionChangeReCalculate != false else { 94 | NSLog("tree is not ready.") 95 | return 96 | } 97 | 98 | guard let aMapView = self?.mapView else { 99 | return 100 | } 101 | 102 | let visibleRect = aMapView.visibleMapRect 103 | let zoomScale = Double(aMapView.bounds.size.width) / visibleRect.size.width 104 | let zoomLevel = Double(aMapView.zoomLevel) 105 | 106 | DispatchQueue.global(qos: .default).async(execute: { [weak self] in 107 | 108 | let annotations = self?.coordinateQuadTree.clusteredAnnotations(within: visibleRect, withZoomScale: zoomScale, andZoomLevel: zoomLevel) 109 | 110 | self?.updateMapViewAnnotations(annotations: annotations as! Array) 111 | }) 112 | } 113 | } 114 | ``` 115 | 116 | - 更新annotations。对比mapView里已有的annotations,吐故纳新。 117 | 118 | `Objective-C` 119 | ```objc 120 | /* 更新annotation. */ 121 | - (void)updateMapViewAnnotationsWithAnnotations:(NSArray *)annotations 122 | { 123 | /* 用户滑动时,保留仍然可用的标注,去除屏幕外标注,添加新增区域的标注 */ 124 | NSMutableSet *before = [NSMutableSet setWithArray:self.mapView.annotations]; 125 | [before removeObject:[self.mapView userLocation]]; 126 | NSSet *after = [NSSet setWithArray:annotations]; 127 | 128 | /* 保留仍然位于屏幕内的annotation. */ 129 | NSMutableSet *toKeep = [NSMutableSet setWithSet:before]; 130 | [toKeep intersectSet:after]; 131 | 132 | /* 需要添加的annotation. */ 133 | NSMutableSet *toAdd = [NSMutableSet setWithSet:after]; 134 | [toAdd minusSet:toKeep]; 135 | 136 | /* 删除位于屏幕外的annotation. */ 137 | NSMutableSet *toRemove = [NSMutableSet setWithSet:before]; 138 | [toRemove minusSet:after]; 139 | 140 | /* 更新. */ 141 | dispatch_async(dispatch_get_main_queue(), ^{ 142 | [self.mapView addAnnotations:[toAdd allObjects]]; 143 | [self.mapView removeAnnotations:[toRemove allObjects]]; 144 | }); 145 | } 146 | ``` 147 | `Swift` 148 | ``` 149 | func updateMapViewAnnotations(annotations: Array) { 150 | 151 | /* 用户滑动时,保留仍然可用的标注,去除屏幕外标注,添加新增区域的标注 */ 152 | let before = NSMutableSet(array: mapView.annotations) 153 | before.remove(mapView.userLocation) 154 | let after: Set = NSSet(array: annotations) as Set 155 | 156 | /* 保留仍然位于屏幕内的annotation. */ 157 | var toKeep: Set = NSMutableSet(set: before) as Set 158 | toKeep = toKeep.intersection(after) 159 | 160 | /* 需要添加的annotation. */ 161 | let toAdd = NSMutableSet(set: after) 162 | toAdd.minus(toKeep) 163 | 164 | /* 删除位于屏幕外的annotation. */ 165 | let toRemove = NSMutableSet(set: before) 166 | toRemove.minus(after) 167 | 168 | DispatchQueue.main.async(execute: { [weak self] () -> Void in 169 | self?.mapView.addAnnotations(toAdd.allObjects) 170 | self?.mapView.removeAnnotations(toRemove.allObjects) 171 | }) 172 | } 173 | ``` 174 | 175 | ### 架构 176 | 177 | ##### Controllers 178 | - `` 179 | * `AnnotationClusterViewController` poi点聚合 180 | * `PoiDetailViewController` 显示poi详细信息列表 181 | 182 | ##### View 183 | 184 | * `MAAnnotationView` 185 | - `ClusterAnnotationView` 自定义的聚合annotationView 186 | 187 | ##### Models 188 | 189 | * `Conform to ` 190 | - `ClusterAnnotation` 记录annotation的信息,如其代表的poi数组、poi的个数、poi平均坐标,并提供两个annotation是否Equal的判断 191 | * `CoordinateQuadTree` 封装的四叉树类 192 | * `QuadTree` 四叉树基本算法 193 | 194 | ### 截图效果 195 | 196 | ![ClusterAnnotation2](https://raw.githubusercontent.com/cysgit/iOS_3D_ClusterAnnotation/master/iOS_3D_ClusterAnnotation/Resources/ClusterAnnotation2.png) 197 | ![ClusterAnnotation1](https://raw.githubusercontent.com/cysgit/iOS_3D_ClusterAnnotation/master/iOS_3D_ClusterAnnotation/Resources/ClusterAnnotation1.png) 198 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/AnnotationClusterViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnnotationClusterViewController.swift 3 | // iOS_ClusterAnnotation_3D 4 | // 5 | // Created by AutoNavi on 2016/12/16. 6 | // Copyright © 2016年 AutoNavi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let calloutViewMargin = -12.0 12 | let buttonHeight = 70.0 13 | 14 | class AnnotationClusterViewController: UIViewController, MAMapViewDelegate, AMapSearchDelegate, CustomCalloutViewTapDelegate { 15 | 16 | var mapView: MAMapView! 17 | var search: AMapSearchAPI! 18 | var refreshButton: UIButton! 19 | 20 | var coordinateQuadTree = CoordinateQuadTree() 21 | var customCalloutView = CustomCalloutView() 22 | var selectedPoiArray = Array() 23 | var shouldRegionChangeReCalculate = false 24 | var currentRequest: AMapPOIKeywordsSearchRequest? 25 | 26 | //MARK: - Update Annotation 27 | 28 | func updateMapViewAnnotations(annotations: Array) { 29 | 30 | /* 用户滑动时,保留仍然可用的标注,去除屏幕外标注,添加新增区域的标注 */ 31 | let before = NSMutableSet(array: mapView.annotations) 32 | before.remove(mapView.userLocation) 33 | let after: Set = NSSet(array: annotations) as Set 34 | 35 | /* 保留仍然位于屏幕内的annotation. */ 36 | var toKeep: Set = NSMutableSet(set: before) as Set 37 | toKeep = toKeep.intersection(after) 38 | 39 | /* 需要添加的annotation. */ 40 | let toAdd = NSMutableSet(set: after) 41 | toAdd.minus(toKeep) 42 | 43 | /* 删除位于屏幕外的annotation. */ 44 | let toRemove = NSMutableSet(set: before) 45 | toRemove.minus(after) 46 | 47 | DispatchQueue.main.async(execute: { [weak self] () -> Void in 48 | self?.mapView.addAnnotations(toAdd.allObjects) 49 | self?.mapView.removeAnnotations(toRemove.allObjects) 50 | }) 51 | } 52 | 53 | func addAnnotations(toMapView mapView: MAMapView) { 54 | synchronized(lock: self) { [weak self] in 55 | 56 | guard (self?.coordinateQuadTree.root != nil) || self?.shouldRegionChangeReCalculate != false else { 57 | NSLog("tree is not ready.") 58 | return 59 | } 60 | 61 | guard let aMapView = self?.mapView else { 62 | return 63 | } 64 | 65 | let visibleRect = aMapView.visibleMapRect 66 | let zoomScale = Double(aMapView.bounds.size.width) / visibleRect.size.width 67 | let zoomLevel = Double(aMapView.zoomLevel) 68 | 69 | DispatchQueue.global(qos: .default).async(execute: { [weak self] in 70 | 71 | let annotations = self?.coordinateQuadTree.clusteredAnnotations(within: visibleRect, withZoomScale: zoomScale, andZoomLevel: zoomLevel) 72 | 73 | self?.updateMapViewAnnotations(annotations: annotations as! Array) 74 | }) 75 | } 76 | } 77 | 78 | func synchronized(lock: AnyObject, closure: () -> ()) { 79 | objc_sync_enter(lock) 80 | closure() 81 | objc_sync_exit(lock) 82 | } 83 | 84 | //MARK: - CustomCalloutViewTapDelegate 85 | 86 | func didDetailButtonTapped(_ index: Int) { 87 | let detail = PoiDetailViewController() 88 | detail.poi = selectedPoiArray[index] 89 | 90 | navigationController?.pushViewController(detail, animated: true) 91 | } 92 | 93 | //MARK: - MAMapViewDelegate 94 | 95 | func mapView(_ mapView: MAMapView!, didSelect view: MAAnnotationView!) { 96 | let annotation = view.annotation as! ClusterAnnotation 97 | 98 | for poi in annotation.pois { 99 | selectedPoiArray.append(poi as! AMapPOI) 100 | } 101 | 102 | customCalloutView.poiArray = selectedPoiArray 103 | customCalloutView.delegate = self 104 | 105 | customCalloutView.center = CGPoint(x: Double(view.bounds.midX), y: -Double(customCalloutView.bounds.midY)-Double(view.bounds.midY)-calloutViewMargin) 106 | 107 | view.addSubview(customCalloutView) 108 | } 109 | 110 | func mapView(_ mapView: MAMapView!, didDeselect view: MAAnnotationView!) { 111 | selectedPoiArray.removeAll() 112 | customCalloutView.dismiss() 113 | customCalloutView.delegate = nil 114 | } 115 | 116 | func mapView(_ mapView: MAMapView!, regionDidChangeAnimated animated: Bool) { 117 | addAnnotations(toMapView: self.mapView) 118 | } 119 | 120 | func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! { 121 | if annotation is ClusterAnnotation { 122 | let pointReuseIndetifier = "pointReuseIndetifier" 123 | 124 | var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) as? ClusterAnnotationView 125 | 126 | if annotationView == nil { 127 | annotationView = ClusterAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier) 128 | } 129 | 130 | annotationView?.annotation = annotation 131 | annotationView?.count = UInt((annotation as! ClusterAnnotation).count) 132 | 133 | return annotationView 134 | } 135 | 136 | return nil 137 | } 138 | 139 | //MARK: - Search POI 140 | 141 | func searchPoi(keywords: String) { 142 | let request = AMapPOIKeywordsSearchRequest() 143 | request.keywords = keywords 144 | request.city = "010" 145 | request.requireExtension = true 146 | 147 | currentRequest = request 148 | search.aMapPOIKeywordsSearch(request) 149 | } 150 | 151 | func onPOISearchDone(_ request: AMapPOISearchBaseRequest!, response: AMapPOISearchResponse!) { 152 | guard response.pois.count > 0 else { 153 | return 154 | } 155 | 156 | guard request == currentRequest else { 157 | return 158 | } 159 | 160 | synchronized(lock: self) { [weak self] in 161 | 162 | self?.shouldRegionChangeReCalculate = false 163 | 164 | self?.selectedPoiArray.removeAll() 165 | self?.customCalloutView.dismiss() 166 | self?.mapView.removeAnnotations(self?.mapView.annotations) 167 | 168 | DispatchQueue.global(qos: .default).async(execute: { [weak self] in 169 | 170 | self?.coordinateQuadTree.build(withPOIs: response.pois) 171 | self?.shouldRegionChangeReCalculate = true 172 | DispatchQueue.main.async(execute: { 173 | self?.addAnnotations(toMapView: (self?.mapView)!) 174 | }) 175 | }) 176 | } 177 | } 178 | 179 | //MARK: - Button Action 180 | 181 | @objc func refreshButtonAction() { 182 | searchPoi(keywords: "Apple") 183 | } 184 | 185 | //MARK: - Init 186 | 187 | override func viewDidLoad() { 188 | super.viewDidLoad() 189 | 190 | initMapView() 191 | 192 | initSearch() 193 | 194 | initRefreshButton() 195 | 196 | refreshButtonAction() 197 | } 198 | 199 | deinit { 200 | coordinateQuadTree.clean() 201 | } 202 | 203 | func initMapView() { 204 | mapView = MAMapView(frame: view.bounds) 205 | mapView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height-CGFloat(buttonHeight)) 206 | mapView.delegate = self 207 | 208 | view.addSubview(mapView) 209 | 210 | mapView.visibleMapRect = MAMapRectMake(220880104, 101476980, 272496, 466656) 211 | } 212 | 213 | func initSearch() { 214 | search = AMapSearchAPI() 215 | search.delegate = self 216 | } 217 | 218 | func initRefreshButton() { 219 | refreshButton = UIButton(type: .custom) 220 | refreshButton.frame = CGRect(x: 0, y: Double(mapView.frame.origin.y+mapView.frame.size.height), width: Double(mapView.frame.size.width), height: buttonHeight) 221 | refreshButton.setTitle("重新加载数据", for: .normal) 222 | refreshButton.setTitleColor(UIColor.purple, for: .normal) 223 | 224 | refreshButton.addTarget(self, action: #selector(self.refreshButtonAction), for: .touchUpInside) 225 | 226 | view.addSubview(refreshButton) 227 | } 228 | 229 | } 230 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS_ClusterAnnotation_3D_Swift 4 | // 5 | // Created by AutoNavi on 2016/12/16. 6 | // Copyright © 2016年 AutoNavi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | 19 | AMapServices.shared().apiKey = APIKey 20 | 21 | let viewController = AnnotationClusterViewController() 22 | 23 | window = UIWindow(frame: UIScreen.main.bounds) 24 | window!.rootViewController = UINavigationController(rootViewController: viewController) 25 | window!.backgroundColor = UIColor.white 26 | window!.makeKeyAndVisible() 27 | 28 | return true 29 | } 30 | 31 | func applicationWillResignActive(_ application: UIApplication) { 32 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 33 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 34 | } 35 | 36 | func applicationDidEnterBackground(_ application: UIApplication) { 37 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | func applicationWillEnterForeground(_ application: UIApplication) { 42 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 43 | } 44 | 45 | func applicationDidBecomeActive(_ application: UIApplication) { 46 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 47 | } 48 | 49 | func applicationWillTerminate(_ application: UIApplication) { 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | } 52 | 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-40x40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-60x60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@3x.png", 49 | "scale" : "3x" 50 | } 51 | ], 52 | "info" : { 53 | "version" : 1, 54 | "author" : "xcode" 55 | } 56 | } -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D-swift/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIRequiredDeviceCapabilities 31 | 32 | armv7 33 | 34 | UISupportedInterfaceOrientations 35 | 36 | UIInterfaceOrientationPortrait 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D-swift/Swift-Bridge-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Swift-Bridge-Header.h 3 | // iOS_ClusterAnnotation_3D 4 | // 5 | // Created by liubo on 2016/12/16. 6 | // Copyright © 2016年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #ifndef Swift_Bridge_Header_h 10 | #define Swift_Bridge_Header_h 11 | 12 | #import 13 | #import 14 | #import 15 | #import "APIKey.h" 16 | 17 | #import "CoordinateQuadTree.h" 18 | #import "ClusterAnnotation.h" 19 | 20 | #import "ClusterAnnotationView.h" 21 | #import "ClusterTableViewCell.h" 22 | #import "CustomCalloutView.h" 23 | #import "PoiDetailViewController.h" 24 | 25 | #endif /* Swift_Bridge_Header_h */ 26 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3946C9F19EF8848A6326C980 /* libPods-iOS_ClusterAnnotation_3D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 544E9E2A7BEEF202588B7814 /* libPods-iOS_ClusterAnnotation_3D.a */; }; 11 | 3AF7AD281E03C5D1001AE58A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD271E03C5D1001AE58A /* main.m */; }; 12 | 3AF7AD2B1E03C5D1001AE58A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD2A1E03C5D1001AE58A /* AppDelegate.m */; }; 13 | 3AF7AD331E03C5D1001AE58A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AF7AD321E03C5D1001AE58A /* Assets.xcassets */; }; 14 | 3AF7AD361E03C5D1001AE58A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3AF7AD341E03C5D1001AE58A /* LaunchScreen.storyboard */; }; 15 | 3AF7AD5E1E03C6E7001AE58A /* AnnotationClusterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD491E03C6E7001AE58A /* AnnotationClusterViewController.m */; }; 16 | 3AF7AD601E03C6E7001AE58A /* PoiDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD4D1E03C6E7001AE58A /* PoiDetailViewController.m */; }; 17 | 3AF7AD611E03C6E7001AE58A /* ClusterAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD501E03C6E7001AE58A /* ClusterAnnotation.m */; }; 18 | 3AF7AD621E03C6E7001AE58A /* CoordinateQuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD521E03C6E7001AE58A /* CoordinateQuadTree.m */; }; 19 | 3AF7AD631E03C6E7001AE58A /* QuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD541E03C6E7001AE58A /* QuadTree.m */; }; 20 | 3AF7AD641E03C6E7001AE58A /* ClusterAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD571E03C6E7001AE58A /* ClusterAnnotationView.m */; }; 21 | 3AF7AD651E03C6E7001AE58A /* ClusterTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD591E03C6E7001AE58A /* ClusterTableViewCell.m */; }; 22 | 3AF7AD661E03C6E7001AE58A /* CustomCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD5B1E03C6E7001AE58A /* CustomCalloutView.m */; }; 23 | 3AF7AD901E04234E001AE58A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD8F1E04234E001AE58A /* AppDelegate.swift */; }; 24 | 3AF7AD971E04234E001AE58A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AF7AD961E04234E001AE58A /* Assets.xcassets */; }; 25 | 3AF7AD9A1E04234E001AE58A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3AF7AD981E04234E001AE58A /* LaunchScreen.storyboard */; }; 26 | 3AF7ADA11E042392001AE58A /* AnnotationClusterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD9F1E042392001AE58A /* AnnotationClusterViewController.swift */; }; 27 | 3AF7ADA21E0423C1001AE58A /* PoiDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD4D1E03C6E7001AE58A /* PoiDetailViewController.m */; }; 28 | 3AF7ADA31E0423C1001AE58A /* ClusterAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD501E03C6E7001AE58A /* ClusterAnnotation.m */; }; 29 | 3AF7ADA41E0423C1001AE58A /* CoordinateQuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD521E03C6E7001AE58A /* CoordinateQuadTree.m */; }; 30 | 3AF7ADA51E0423C1001AE58A /* QuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD541E03C6E7001AE58A /* QuadTree.m */; }; 31 | 3AF7ADA61E0423C1001AE58A /* ClusterAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD571E03C6E7001AE58A /* ClusterAnnotationView.m */; }; 32 | 3AF7ADA71E0423C1001AE58A /* ClusterTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD591E03C6E7001AE58A /* ClusterTableViewCell.m */; }; 33 | 3AF7ADA81E0423C1001AE58A /* CustomCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF7AD5B1E03C6E7001AE58A /* CustomCalloutView.m */; }; 34 | 6A6C53B81E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A6C53B71E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.m */; }; 35 | E5DCD0EBD5009218FD11BBDE /* libPods-iOS_ClusterAnnotation_3D-swift.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD7FB35C2D5137EAC266EE59 /* libPods-iOS_ClusterAnnotation_3D-swift.a */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXContainerItemProxy section */ 39 | 6A6C53BA1E08CF1800739D47 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 3AF7AD1B1E03C5D1001AE58A /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = 3AF7AD221E03C5D1001AE58A; 44 | remoteInfo = iOS_ClusterAnnotation_3D; 45 | }; 46 | /* End PBXContainerItemProxy section */ 47 | 48 | /* Begin PBXFileReference section */ 49 | 3813129DDA80BB5079C86E73 /* Pods-iOS_ClusterAnnotation_3D.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS_ClusterAnnotation_3D.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS_ClusterAnnotation_3D/Pods-iOS_ClusterAnnotation_3D.debug.xcconfig"; sourceTree = ""; }; 50 | 3AF7AD231E03C5D1001AE58A /* iOS_ClusterAnnotation_3D.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOS_ClusterAnnotation_3D.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 3AF7AD271E03C5D1001AE58A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 52 | 3AF7AD291E03C5D1001AE58A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 53 | 3AF7AD2A1E03C5D1001AE58A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 54 | 3AF7AD321E03C5D1001AE58A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 55 | 3AF7AD351E03C5D1001AE58A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 56 | 3AF7AD371E03C5D1001AE58A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 3AF7AD481E03C6E7001AE58A /* AnnotationClusterViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnnotationClusterViewController.h; sourceTree = ""; }; 58 | 3AF7AD491E03C6E7001AE58A /* AnnotationClusterViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnnotationClusterViewController.m; sourceTree = ""; }; 59 | 3AF7AD4C1E03C6E7001AE58A /* PoiDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoiDetailViewController.h; sourceTree = ""; }; 60 | 3AF7AD4D1E03C6E7001AE58A /* PoiDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PoiDetailViewController.m; sourceTree = ""; }; 61 | 3AF7AD4F1E03C6E7001AE58A /* ClusterAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClusterAnnotation.h; sourceTree = ""; }; 62 | 3AF7AD501E03C6E7001AE58A /* ClusterAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClusterAnnotation.m; sourceTree = ""; }; 63 | 3AF7AD511E03C6E7001AE58A /* CoordinateQuadTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoordinateQuadTree.h; sourceTree = ""; }; 64 | 3AF7AD521E03C6E7001AE58A /* CoordinateQuadTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoordinateQuadTree.m; sourceTree = ""; }; 65 | 3AF7AD531E03C6E7001AE58A /* QuadTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuadTree.h; sourceTree = ""; }; 66 | 3AF7AD541E03C6E7001AE58A /* QuadTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuadTree.m; sourceTree = ""; }; 67 | 3AF7AD561E03C6E7001AE58A /* ClusterAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClusterAnnotationView.h; sourceTree = ""; }; 68 | 3AF7AD571E03C6E7001AE58A /* ClusterAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClusterAnnotationView.m; sourceTree = ""; }; 69 | 3AF7AD581E03C6E7001AE58A /* ClusterTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClusterTableViewCell.h; sourceTree = ""; }; 70 | 3AF7AD591E03C6E7001AE58A /* ClusterTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClusterTableViewCell.m; sourceTree = ""; }; 71 | 3AF7AD5A1E03C6E7001AE58A /* CustomCalloutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomCalloutView.h; sourceTree = ""; }; 72 | 3AF7AD5B1E03C6E7001AE58A /* CustomCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomCalloutView.m; sourceTree = ""; }; 73 | 3AF7AD5D1E03C6E7001AE58A /* APIKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIKey.h; sourceTree = ""; }; 74 | 3AF7AD8D1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS_ClusterAnnotation_3D-swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 3AF7AD8F1E04234E001AE58A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 76 | 3AF7AD961E04234E001AE58A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 77 | 3AF7AD991E04234E001AE58A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 78 | 3AF7AD9B1E04234E001AE58A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 79 | 3AF7AD9F1E042392001AE58A /* AnnotationClusterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnnotationClusterViewController.swift; sourceTree = ""; }; 80 | 3AF7ADA01E042392001AE58A /* Swift-Bridge-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Swift-Bridge-Header.h"; sourceTree = ""; }; 81 | 4B042D552FAD6B5D99ADD97E /* Pods-iOS_ClusterAnnotation_3D-swift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS_ClusterAnnotation_3D-swift.release.xcconfig"; path = "Pods/Target Support Files/Pods-iOS_ClusterAnnotation_3D-swift/Pods-iOS_ClusterAnnotation_3D-swift.release.xcconfig"; sourceTree = ""; }; 82 | 544E9E2A7BEEF202588B7814 /* libPods-iOS_ClusterAnnotation_3D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-iOS_ClusterAnnotation_3D.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 6A6C53B51E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOS_ClusterAnnotation_3DUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 6A6C53B71E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOS_ClusterAnnotation_3DUITests.m; sourceTree = ""; }; 85 | 6A6C53B91E08CF1800739D47 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | 7912C4F4E8063C21C463E2C0 /* Pods-iOS_ClusterAnnotation_3D.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS_ClusterAnnotation_3D.release.xcconfig"; path = "Pods/Target Support Files/Pods-iOS_ClusterAnnotation_3D/Pods-iOS_ClusterAnnotation_3D.release.xcconfig"; sourceTree = ""; }; 87 | A5E2D4BA8FA2CC10EEFBFCB7 /* Pods-iOS_ClusterAnnotation_3D-swift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS_ClusterAnnotation_3D-swift.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS_ClusterAnnotation_3D-swift/Pods-iOS_ClusterAnnotation_3D-swift.debug.xcconfig"; sourceTree = ""; }; 88 | CD7FB35C2D5137EAC266EE59 /* libPods-iOS_ClusterAnnotation_3D-swift.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-iOS_ClusterAnnotation_3D-swift.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | FD2A8A52B85A6A85EC6A3D48 /* libPods-iOS_ClusterAnnotation_3D_Swift.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-iOS_ClusterAnnotation_3D_Swift.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 90 | /* End PBXFileReference section */ 91 | 92 | /* Begin PBXFrameworksBuildPhase section */ 93 | 3AF7AD201E03C5D1001AE58A /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | 3946C9F19EF8848A6326C980 /* libPods-iOS_ClusterAnnotation_3D.a in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | 3AF7AD8A1E04234E001AE58A /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | E5DCD0EBD5009218FD11BBDE /* libPods-iOS_ClusterAnnotation_3D-swift.a in Frameworks */, 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | 6A6C53B21E08CF1800739D47 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | /* End PBXFrameworksBuildPhase section */ 117 | 118 | /* Begin PBXGroup section */ 119 | 3AF7AD1A1E03C5D1001AE58A = { 120 | isa = PBXGroup; 121 | children = ( 122 | 3AF7AD251E03C5D1001AE58A /* iOS_ClusterAnnotation_3D */, 123 | 3AF7AD8E1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift */, 124 | 6A6C53B61E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests */, 125 | 3AF7AD241E03C5D1001AE58A /* Products */, 126 | 6A499FB89E7E71D456730A17 /* Pods */, 127 | DF7E5EC566538DB8C00BEFEF /* Frameworks */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | 3AF7AD241E03C5D1001AE58A /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 3AF7AD231E03C5D1001AE58A /* iOS_ClusterAnnotation_3D.app */, 135 | 3AF7AD8D1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift.app */, 136 | 6A6C53B51E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.xctest */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | 3AF7AD251E03C5D1001AE58A /* iOS_ClusterAnnotation_3D */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 3AF7AD291E03C5D1001AE58A /* AppDelegate.h */, 145 | 3AF7AD2A1E03C5D1001AE58A /* AppDelegate.m */, 146 | 3AF7AD451E03C6E7001AE58A /* ClusterAnnotation */, 147 | 3AF7AD5C1E03C6E7001AE58A /* Configuration */, 148 | 3AF7AD321E03C5D1001AE58A /* Assets.xcassets */, 149 | 3AF7AD341E03C5D1001AE58A /* LaunchScreen.storyboard */, 150 | 3AF7AD371E03C5D1001AE58A /* Info.plist */, 151 | 3AF7AD261E03C5D1001AE58A /* Supporting Files */, 152 | ); 153 | path = iOS_ClusterAnnotation_3D; 154 | sourceTree = ""; 155 | }; 156 | 3AF7AD261E03C5D1001AE58A /* Supporting Files */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 3AF7AD271E03C5D1001AE58A /* main.m */, 160 | ); 161 | name = "Supporting Files"; 162 | sourceTree = ""; 163 | }; 164 | 3AF7AD451E03C6E7001AE58A /* ClusterAnnotation */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 3AF7AD461E03C6E7001AE58A /* Demo */, 168 | 3AF7AD4E1E03C6E7001AE58A /* Model */, 169 | 3AF7AD551E03C6E7001AE58A /* View */, 170 | ); 171 | path = ClusterAnnotation; 172 | sourceTree = ""; 173 | }; 174 | 3AF7AD461E03C6E7001AE58A /* Demo */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 3AF7AD471E03C6E7001AE58A /* Controller */, 178 | ); 179 | path = Demo; 180 | sourceTree = ""; 181 | }; 182 | 3AF7AD471E03C6E7001AE58A /* Controller */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 3AF7AD481E03C6E7001AE58A /* AnnotationClusterViewController.h */, 186 | 3AF7AD491E03C6E7001AE58A /* AnnotationClusterViewController.m */, 187 | 3AF7AD4C1E03C6E7001AE58A /* PoiDetailViewController.h */, 188 | 3AF7AD4D1E03C6E7001AE58A /* PoiDetailViewController.m */, 189 | ); 190 | path = Controller; 191 | sourceTree = ""; 192 | }; 193 | 3AF7AD4E1E03C6E7001AE58A /* Model */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 3AF7AD4F1E03C6E7001AE58A /* ClusterAnnotation.h */, 197 | 3AF7AD501E03C6E7001AE58A /* ClusterAnnotation.m */, 198 | 3AF7AD511E03C6E7001AE58A /* CoordinateQuadTree.h */, 199 | 3AF7AD521E03C6E7001AE58A /* CoordinateQuadTree.m */, 200 | 3AF7AD531E03C6E7001AE58A /* QuadTree.h */, 201 | 3AF7AD541E03C6E7001AE58A /* QuadTree.m */, 202 | ); 203 | path = Model; 204 | sourceTree = ""; 205 | }; 206 | 3AF7AD551E03C6E7001AE58A /* View */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 3AF7AD561E03C6E7001AE58A /* ClusterAnnotationView.h */, 210 | 3AF7AD571E03C6E7001AE58A /* ClusterAnnotationView.m */, 211 | 3AF7AD581E03C6E7001AE58A /* ClusterTableViewCell.h */, 212 | 3AF7AD591E03C6E7001AE58A /* ClusterTableViewCell.m */, 213 | 3AF7AD5A1E03C6E7001AE58A /* CustomCalloutView.h */, 214 | 3AF7AD5B1E03C6E7001AE58A /* CustomCalloutView.m */, 215 | ); 216 | path = View; 217 | sourceTree = ""; 218 | }; 219 | 3AF7AD5C1E03C6E7001AE58A /* Configuration */ = { 220 | isa = PBXGroup; 221 | children = ( 222 | 3AF7AD5D1E03C6E7001AE58A /* APIKey.h */, 223 | ); 224 | path = Configuration; 225 | sourceTree = ""; 226 | }; 227 | 3AF7AD8E1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | 3AF7AD8F1E04234E001AE58A /* AppDelegate.swift */, 231 | 3AF7AD9F1E042392001AE58A /* AnnotationClusterViewController.swift */, 232 | 3AF7ADA01E042392001AE58A /* Swift-Bridge-Header.h */, 233 | 3AF7AD961E04234E001AE58A /* Assets.xcassets */, 234 | 3AF7AD981E04234E001AE58A /* LaunchScreen.storyboard */, 235 | 3AF7AD9B1E04234E001AE58A /* Info.plist */, 236 | ); 237 | path = "iOS_ClusterAnnotation_3D-swift"; 238 | sourceTree = ""; 239 | }; 240 | 6A499FB89E7E71D456730A17 /* Pods */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 3813129DDA80BB5079C86E73 /* Pods-iOS_ClusterAnnotation_3D.debug.xcconfig */, 244 | 7912C4F4E8063C21C463E2C0 /* Pods-iOS_ClusterAnnotation_3D.release.xcconfig */, 245 | A5E2D4BA8FA2CC10EEFBFCB7 /* Pods-iOS_ClusterAnnotation_3D-swift.debug.xcconfig */, 246 | 4B042D552FAD6B5D99ADD97E /* Pods-iOS_ClusterAnnotation_3D-swift.release.xcconfig */, 247 | ); 248 | name = Pods; 249 | sourceTree = ""; 250 | }; 251 | 6A6C53B61E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 6A6C53B71E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.m */, 255 | 6A6C53B91E08CF1800739D47 /* Info.plist */, 256 | ); 257 | path = iOS_ClusterAnnotation_3DUITests; 258 | sourceTree = ""; 259 | }; 260 | DF7E5EC566538DB8C00BEFEF /* Frameworks */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | 544E9E2A7BEEF202588B7814 /* libPods-iOS_ClusterAnnotation_3D.a */, 264 | FD2A8A52B85A6A85EC6A3D48 /* libPods-iOS_ClusterAnnotation_3D_Swift.a */, 265 | CD7FB35C2D5137EAC266EE59 /* libPods-iOS_ClusterAnnotation_3D-swift.a */, 266 | ); 267 | name = Frameworks; 268 | sourceTree = ""; 269 | }; 270 | /* End PBXGroup section */ 271 | 272 | /* Begin PBXNativeTarget section */ 273 | 3AF7AD221E03C5D1001AE58A /* iOS_ClusterAnnotation_3D */ = { 274 | isa = PBXNativeTarget; 275 | buildConfigurationList = 3AF7AD3A1E03C5D1001AE58A /* Build configuration list for PBXNativeTarget "iOS_ClusterAnnotation_3D" */; 276 | buildPhases = ( 277 | 3A80B241C7A0410E696DA69C /* [CP] Check Pods Manifest.lock */, 278 | 3AF7AD1F1E03C5D1001AE58A /* Sources */, 279 | 3AF7AD201E03C5D1001AE58A /* Frameworks */, 280 | 3AF7AD211E03C5D1001AE58A /* Resources */, 281 | 764AD1E42792A7865A78526F /* [CP] Copy Pods Resources */, 282 | ); 283 | buildRules = ( 284 | ); 285 | dependencies = ( 286 | ); 287 | name = iOS_ClusterAnnotation_3D; 288 | productName = iOS_ClusterAnnotation_3D; 289 | productReference = 3AF7AD231E03C5D1001AE58A /* iOS_ClusterAnnotation_3D.app */; 290 | productType = "com.apple.product-type.application"; 291 | }; 292 | 3AF7AD8C1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift */ = { 293 | isa = PBXNativeTarget; 294 | buildConfigurationList = 3AF7AD9C1E04234E001AE58A /* Build configuration list for PBXNativeTarget "iOS_ClusterAnnotation_3D-swift" */; 295 | buildPhases = ( 296 | 18A6CF15DC983967739BFD87 /* [CP] Check Pods Manifest.lock */, 297 | 3AF7AD891E04234E001AE58A /* Sources */, 298 | 3AF7AD8A1E04234E001AE58A /* Frameworks */, 299 | 3AF7AD8B1E04234E001AE58A /* Resources */, 300 | 3F95B58E82C374CDA6D9E3FC /* [CP] Copy Pods Resources */, 301 | ); 302 | buildRules = ( 303 | ); 304 | dependencies = ( 305 | ); 306 | name = "iOS_ClusterAnnotation_3D-swift"; 307 | productName = "iOS_ClusterAnnotation_3D-swift"; 308 | productReference = 3AF7AD8D1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift.app */; 309 | productType = "com.apple.product-type.application"; 310 | }; 311 | 6A6C53B41E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests */ = { 312 | isa = PBXNativeTarget; 313 | buildConfigurationList = 6A6C53BE1E08CF1800739D47 /* Build configuration list for PBXNativeTarget "iOS_ClusterAnnotation_3DUITests" */; 314 | buildPhases = ( 315 | 6A6C53B11E08CF1800739D47 /* Sources */, 316 | 6A6C53B21E08CF1800739D47 /* Frameworks */, 317 | 6A6C53B31E08CF1800739D47 /* Resources */, 318 | ); 319 | buildRules = ( 320 | ); 321 | dependencies = ( 322 | 6A6C53BB1E08CF1800739D47 /* PBXTargetDependency */, 323 | ); 324 | name = iOS_ClusterAnnotation_3DUITests; 325 | productName = iOS_ClusterAnnotation_3DUITests; 326 | productReference = 6A6C53B51E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.xctest */; 327 | productType = "com.apple.product-type.bundle.ui-testing"; 328 | }; 329 | /* End PBXNativeTarget section */ 330 | 331 | /* Begin PBXProject section */ 332 | 3AF7AD1B1E03C5D1001AE58A /* Project object */ = { 333 | isa = PBXProject; 334 | attributes = { 335 | LastSwiftUpdateCheck = 0810; 336 | LastUpgradeCheck = 0900; 337 | ORGANIZATIONNAME = AutoNavi; 338 | TargetAttributes = { 339 | 3AF7AD221E03C5D1001AE58A = { 340 | CreatedOnToolsVersion = 8.1; 341 | DevelopmentTeam = YMJ372W38W; 342 | ProvisioningStyle = Manual; 343 | }; 344 | 3AF7AD8C1E04234E001AE58A = { 345 | CreatedOnToolsVersion = 8.1; 346 | DevelopmentTeam = YMJ372W38W; 347 | ProvisioningStyle = Manual; 348 | }; 349 | 6A6C53B41E08CF1800739D47 = { 350 | CreatedOnToolsVersion = 8.1; 351 | DevelopmentTeam = YMJ372W38W; 352 | ProvisioningStyle = Manual; 353 | TestTargetID = 3AF7AD221E03C5D1001AE58A; 354 | }; 355 | }; 356 | }; 357 | buildConfigurationList = 3AF7AD1E1E03C5D1001AE58A /* Build configuration list for PBXProject "iOS_ClusterAnnotation_3D" */; 358 | compatibilityVersion = "Xcode 3.2"; 359 | developmentRegion = English; 360 | hasScannedForEncodings = 0; 361 | knownRegions = ( 362 | English, 363 | en, 364 | Base, 365 | ); 366 | mainGroup = 3AF7AD1A1E03C5D1001AE58A; 367 | productRefGroup = 3AF7AD241E03C5D1001AE58A /* Products */; 368 | projectDirPath = ""; 369 | projectRoot = ""; 370 | targets = ( 371 | 3AF7AD221E03C5D1001AE58A /* iOS_ClusterAnnotation_3D */, 372 | 3AF7AD8C1E04234E001AE58A /* iOS_ClusterAnnotation_3D-swift */, 373 | 6A6C53B41E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests */, 374 | ); 375 | }; 376 | /* End PBXProject section */ 377 | 378 | /* Begin PBXResourcesBuildPhase section */ 379 | 3AF7AD211E03C5D1001AE58A /* Resources */ = { 380 | isa = PBXResourcesBuildPhase; 381 | buildActionMask = 2147483647; 382 | files = ( 383 | 3AF7AD361E03C5D1001AE58A /* LaunchScreen.storyboard in Resources */, 384 | 3AF7AD331E03C5D1001AE58A /* Assets.xcassets in Resources */, 385 | ); 386 | runOnlyForDeploymentPostprocessing = 0; 387 | }; 388 | 3AF7AD8B1E04234E001AE58A /* Resources */ = { 389 | isa = PBXResourcesBuildPhase; 390 | buildActionMask = 2147483647; 391 | files = ( 392 | 3AF7AD9A1E04234E001AE58A /* LaunchScreen.storyboard in Resources */, 393 | 3AF7AD971E04234E001AE58A /* Assets.xcassets in Resources */, 394 | ); 395 | runOnlyForDeploymentPostprocessing = 0; 396 | }; 397 | 6A6C53B31E08CF1800739D47 /* Resources */ = { 398 | isa = PBXResourcesBuildPhase; 399 | buildActionMask = 2147483647; 400 | files = ( 401 | ); 402 | runOnlyForDeploymentPostprocessing = 0; 403 | }; 404 | /* End PBXResourcesBuildPhase section */ 405 | 406 | /* Begin PBXShellScriptBuildPhase section */ 407 | 18A6CF15DC983967739BFD87 /* [CP] Check Pods Manifest.lock */ = { 408 | isa = PBXShellScriptBuildPhase; 409 | buildActionMask = 2147483647; 410 | files = ( 411 | ); 412 | inputPaths = ( 413 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 414 | "${PODS_ROOT}/Manifest.lock", 415 | ); 416 | name = "[CP] Check Pods Manifest.lock"; 417 | outputPaths = ( 418 | "$(DERIVED_FILE_DIR)/Pods-iOS_ClusterAnnotation_3D-swift-checkManifestLockResult.txt", 419 | ); 420 | runOnlyForDeploymentPostprocessing = 0; 421 | shellPath = /bin/sh; 422 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 423 | showEnvVarsInLog = 0; 424 | }; 425 | 3A80B241C7A0410E696DA69C /* [CP] Check Pods Manifest.lock */ = { 426 | isa = PBXShellScriptBuildPhase; 427 | buildActionMask = 2147483647; 428 | files = ( 429 | ); 430 | inputPaths = ( 431 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 432 | "${PODS_ROOT}/Manifest.lock", 433 | ); 434 | name = "[CP] Check Pods Manifest.lock"; 435 | outputPaths = ( 436 | "$(DERIVED_FILE_DIR)/Pods-iOS_ClusterAnnotation_3D-checkManifestLockResult.txt", 437 | ); 438 | runOnlyForDeploymentPostprocessing = 0; 439 | shellPath = /bin/sh; 440 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 441 | showEnvVarsInLog = 0; 442 | }; 443 | 3F95B58E82C374CDA6D9E3FC /* [CP] Copy Pods Resources */ = { 444 | isa = PBXShellScriptBuildPhase; 445 | buildActionMask = 2147483647; 446 | files = ( 447 | ); 448 | inputPaths = ( 449 | "${PODS_ROOT}/Target Support Files/Pods-iOS_ClusterAnnotation_3D-swift/Pods-iOS_ClusterAnnotation_3D-swift-resources.sh", 450 | "${PODS_ROOT}/AMap3DMap/MAMapKit.framework/AMap.bundle", 451 | ); 452 | name = "[CP] Copy Pods Resources"; 453 | outputPaths = ( 454 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AMap.bundle", 455 | ); 456 | runOnlyForDeploymentPostprocessing = 0; 457 | shellPath = /bin/sh; 458 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS_ClusterAnnotation_3D-swift/Pods-iOS_ClusterAnnotation_3D-swift-resources.sh\"\n"; 459 | showEnvVarsInLog = 0; 460 | }; 461 | 764AD1E42792A7865A78526F /* [CP] Copy Pods Resources */ = { 462 | isa = PBXShellScriptBuildPhase; 463 | buildActionMask = 2147483647; 464 | files = ( 465 | ); 466 | inputPaths = ( 467 | "${PODS_ROOT}/Target Support Files/Pods-iOS_ClusterAnnotation_3D/Pods-iOS_ClusterAnnotation_3D-resources.sh", 468 | "${PODS_ROOT}/AMap3DMap/MAMapKit.framework/AMap.bundle", 469 | ); 470 | name = "[CP] Copy Pods Resources"; 471 | outputPaths = ( 472 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AMap.bundle", 473 | ); 474 | runOnlyForDeploymentPostprocessing = 0; 475 | shellPath = /bin/sh; 476 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS_ClusterAnnotation_3D/Pods-iOS_ClusterAnnotation_3D-resources.sh\"\n"; 477 | showEnvVarsInLog = 0; 478 | }; 479 | /* End PBXShellScriptBuildPhase section */ 480 | 481 | /* Begin PBXSourcesBuildPhase section */ 482 | 3AF7AD1F1E03C5D1001AE58A /* Sources */ = { 483 | isa = PBXSourcesBuildPhase; 484 | buildActionMask = 2147483647; 485 | files = ( 486 | 3AF7AD661E03C6E7001AE58A /* CustomCalloutView.m in Sources */, 487 | 3AF7AD641E03C6E7001AE58A /* ClusterAnnotationView.m in Sources */, 488 | 3AF7AD611E03C6E7001AE58A /* ClusterAnnotation.m in Sources */, 489 | 3AF7AD5E1E03C6E7001AE58A /* AnnotationClusterViewController.m in Sources */, 490 | 3AF7AD621E03C6E7001AE58A /* CoordinateQuadTree.m in Sources */, 491 | 3AF7AD651E03C6E7001AE58A /* ClusterTableViewCell.m in Sources */, 492 | 3AF7AD2B1E03C5D1001AE58A /* AppDelegate.m in Sources */, 493 | 3AF7AD631E03C6E7001AE58A /* QuadTree.m in Sources */, 494 | 3AF7AD601E03C6E7001AE58A /* PoiDetailViewController.m in Sources */, 495 | 3AF7AD281E03C5D1001AE58A /* main.m in Sources */, 496 | ); 497 | runOnlyForDeploymentPostprocessing = 0; 498 | }; 499 | 3AF7AD891E04234E001AE58A /* Sources */ = { 500 | isa = PBXSourcesBuildPhase; 501 | buildActionMask = 2147483647; 502 | files = ( 503 | 3AF7ADA21E0423C1001AE58A /* PoiDetailViewController.m in Sources */, 504 | 3AF7ADA31E0423C1001AE58A /* ClusterAnnotation.m in Sources */, 505 | 3AF7ADA41E0423C1001AE58A /* CoordinateQuadTree.m in Sources */, 506 | 3AF7ADA51E0423C1001AE58A /* QuadTree.m in Sources */, 507 | 3AF7ADA61E0423C1001AE58A /* ClusterAnnotationView.m in Sources */, 508 | 3AF7ADA71E0423C1001AE58A /* ClusterTableViewCell.m in Sources */, 509 | 3AF7ADA81E0423C1001AE58A /* CustomCalloutView.m in Sources */, 510 | 3AF7ADA11E042392001AE58A /* AnnotationClusterViewController.swift in Sources */, 511 | 3AF7AD901E04234E001AE58A /* AppDelegate.swift in Sources */, 512 | ); 513 | runOnlyForDeploymentPostprocessing = 0; 514 | }; 515 | 6A6C53B11E08CF1800739D47 /* Sources */ = { 516 | isa = PBXSourcesBuildPhase; 517 | buildActionMask = 2147483647; 518 | files = ( 519 | 6A6C53B81E08CF1800739D47 /* iOS_ClusterAnnotation_3DUITests.m in Sources */, 520 | ); 521 | runOnlyForDeploymentPostprocessing = 0; 522 | }; 523 | /* End PBXSourcesBuildPhase section */ 524 | 525 | /* Begin PBXTargetDependency section */ 526 | 6A6C53BB1E08CF1800739D47 /* PBXTargetDependency */ = { 527 | isa = PBXTargetDependency; 528 | target = 3AF7AD221E03C5D1001AE58A /* iOS_ClusterAnnotation_3D */; 529 | targetProxy = 6A6C53BA1E08CF1800739D47 /* PBXContainerItemProxy */; 530 | }; 531 | /* End PBXTargetDependency section */ 532 | 533 | /* Begin PBXVariantGroup section */ 534 | 3AF7AD341E03C5D1001AE58A /* LaunchScreen.storyboard */ = { 535 | isa = PBXVariantGroup; 536 | children = ( 537 | 3AF7AD351E03C5D1001AE58A /* Base */, 538 | ); 539 | name = LaunchScreen.storyboard; 540 | sourceTree = ""; 541 | }; 542 | 3AF7AD981E04234E001AE58A /* LaunchScreen.storyboard */ = { 543 | isa = PBXVariantGroup; 544 | children = ( 545 | 3AF7AD991E04234E001AE58A /* Base */, 546 | ); 547 | name = LaunchScreen.storyboard; 548 | sourceTree = ""; 549 | }; 550 | /* End PBXVariantGroup section */ 551 | 552 | /* Begin XCBuildConfiguration section */ 553 | 3AF7AD381E03C5D1001AE58A /* Debug */ = { 554 | isa = XCBuildConfiguration; 555 | buildSettings = { 556 | ALWAYS_SEARCH_USER_PATHS = NO; 557 | CLANG_ANALYZER_NONNULL = YES; 558 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 559 | CLANG_CXX_LIBRARY = "libc++"; 560 | CLANG_ENABLE_MODULES = YES; 561 | CLANG_ENABLE_OBJC_ARC = YES; 562 | CLANG_WARN_BOOL_CONVERSION = YES; 563 | CLANG_WARN_CONSTANT_CONVERSION = YES; 564 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 565 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 566 | CLANG_WARN_EMPTY_BODY = YES; 567 | CLANG_WARN_ENUM_CONVERSION = YES; 568 | CLANG_WARN_INFINITE_RECURSION = YES; 569 | CLANG_WARN_INT_CONVERSION = YES; 570 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 571 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 572 | CLANG_WARN_UNREACHABLE_CODE = YES; 573 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 574 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 575 | COPY_PHASE_STRIP = NO; 576 | DEBUG_INFORMATION_FORMAT = dwarf; 577 | ENABLE_STRICT_OBJC_MSGSEND = YES; 578 | ENABLE_TESTABILITY = YES; 579 | GCC_C_LANGUAGE_STANDARD = gnu99; 580 | GCC_DYNAMIC_NO_PIC = NO; 581 | GCC_NO_COMMON_BLOCKS = YES; 582 | GCC_OPTIMIZATION_LEVEL = 0; 583 | GCC_PREPROCESSOR_DEFINITIONS = ( 584 | "DEBUG=1", 585 | "$(inherited)", 586 | ); 587 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 588 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 589 | GCC_WARN_UNDECLARED_SELECTOR = YES; 590 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 591 | GCC_WARN_UNUSED_FUNCTION = YES; 592 | GCC_WARN_UNUSED_VARIABLE = YES; 593 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 594 | MTL_ENABLE_DEBUG_INFO = YES; 595 | ONLY_ACTIVE_ARCH = YES; 596 | SDKROOT = iphoneos; 597 | }; 598 | name = Debug; 599 | }; 600 | 3AF7AD391E03C5D1001AE58A /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | ALWAYS_SEARCH_USER_PATHS = NO; 604 | CLANG_ANALYZER_NONNULL = YES; 605 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 606 | CLANG_CXX_LIBRARY = "libc++"; 607 | CLANG_ENABLE_MODULES = YES; 608 | CLANG_ENABLE_OBJC_ARC = YES; 609 | CLANG_WARN_BOOL_CONVERSION = YES; 610 | CLANG_WARN_CONSTANT_CONVERSION = YES; 611 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 612 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 613 | CLANG_WARN_EMPTY_BODY = YES; 614 | CLANG_WARN_ENUM_CONVERSION = YES; 615 | CLANG_WARN_INFINITE_RECURSION = YES; 616 | CLANG_WARN_INT_CONVERSION = YES; 617 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 618 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 619 | CLANG_WARN_UNREACHABLE_CODE = YES; 620 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 621 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 622 | COPY_PHASE_STRIP = NO; 623 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 624 | ENABLE_NS_ASSERTIONS = NO; 625 | ENABLE_STRICT_OBJC_MSGSEND = YES; 626 | GCC_C_LANGUAGE_STANDARD = gnu99; 627 | GCC_NO_COMMON_BLOCKS = YES; 628 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 629 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 630 | GCC_WARN_UNDECLARED_SELECTOR = YES; 631 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 632 | GCC_WARN_UNUSED_FUNCTION = YES; 633 | GCC_WARN_UNUSED_VARIABLE = YES; 634 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 635 | MTL_ENABLE_DEBUG_INFO = NO; 636 | SDKROOT = iphoneos; 637 | VALIDATE_PRODUCT = YES; 638 | }; 639 | name = Release; 640 | }; 641 | 3AF7AD3B1E03C5D1001AE58A /* Debug */ = { 642 | isa = XCBuildConfiguration; 643 | baseConfigurationReference = 3813129DDA80BB5079C86E73 /* Pods-iOS_ClusterAnnotation_3D.debug.xcconfig */; 644 | buildSettings = { 645 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 646 | DEVELOPMENT_TEAM = YMJ372W38W; 647 | INFOPLIST_FILE = iOS_ClusterAnnotation_3D/Info.plist; 648 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 649 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 650 | PRODUCT_BUNDLE_IDENTIFIER = "com.autonavi.iOS-ClusterAnnotation-3D"; 651 | PRODUCT_NAME = "$(TARGET_NAME)"; 652 | PROVISIONING_PROFILE = "249676f7-6dfc-4adf-ab62-14190fd9ac21"; 653 | PROVISIONING_PROFILE_SPECIFIER = openPlatform_development; 654 | }; 655 | name = Debug; 656 | }; 657 | 3AF7AD3C1E03C5D1001AE58A /* Release */ = { 658 | isa = XCBuildConfiguration; 659 | baseConfigurationReference = 7912C4F4E8063C21C463E2C0 /* Pods-iOS_ClusterAnnotation_3D.release.xcconfig */; 660 | buildSettings = { 661 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 662 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; 663 | DEVELOPMENT_TEAM = YMJ372W38W; 664 | INFOPLIST_FILE = iOS_ClusterAnnotation_3D/Info.plist; 665 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 666 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 667 | PRODUCT_BUNDLE_IDENTIFIER = "com.autonavi.iOS-ClusterAnnotation-3D"; 668 | PRODUCT_NAME = "$(TARGET_NAME)"; 669 | PROVISIONING_PROFILE = "a892512d-fe94-4702-b716-0b66880b936d"; 670 | PROVISIONING_PROFILE_SPECIFIER = openPlatformInhouse; 671 | }; 672 | name = Release; 673 | }; 674 | 3AF7AD9D1E04234E001AE58A /* Debug */ = { 675 | isa = XCBuildConfiguration; 676 | baseConfigurationReference = A5E2D4BA8FA2CC10EEFBFCB7 /* Pods-iOS_ClusterAnnotation_3D-swift.debug.xcconfig */; 677 | buildSettings = { 678 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 679 | DEVELOPMENT_TEAM = YMJ372W38W; 680 | INFOPLIST_FILE = "iOS_ClusterAnnotation_3D-swift/Info.plist"; 681 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 682 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 683 | PRODUCT_BUNDLE_IDENTIFIER = "com.autonavi.iOS-ClusterAnnotation-3D"; 684 | PRODUCT_NAME = "$(TARGET_NAME)"; 685 | PROVISIONING_PROFILE = "249676f7-6dfc-4adf-ab62-14190fd9ac21"; 686 | PROVISIONING_PROFILE_SPECIFIER = openPlatform_development; 687 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 688 | SWIFT_OBJC_BRIDGING_HEADER = "iOS_ClusterAnnotation_3D-swift/Swift-Bridge-Header.h"; 689 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 690 | SWIFT_VERSION = 4.0; 691 | }; 692 | name = Debug; 693 | }; 694 | 3AF7AD9E1E04234E001AE58A /* Release */ = { 695 | isa = XCBuildConfiguration; 696 | baseConfigurationReference = 4B042D552FAD6B5D99ADD97E /* Pods-iOS_ClusterAnnotation_3D-swift.release.xcconfig */; 697 | buildSettings = { 698 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 699 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; 700 | DEVELOPMENT_TEAM = YMJ372W38W; 701 | INFOPLIST_FILE = "iOS_ClusterAnnotation_3D-swift/Info.plist"; 702 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 703 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 704 | PRODUCT_BUNDLE_IDENTIFIER = "com.autonavi.iOS-ClusterAnnotation-3D"; 705 | PRODUCT_NAME = "$(TARGET_NAME)"; 706 | PROVISIONING_PROFILE = "a892512d-fe94-4702-b716-0b66880b936d"; 707 | PROVISIONING_PROFILE_SPECIFIER = openPlatformInhouse; 708 | SWIFT_OBJC_BRIDGING_HEADER = "iOS_ClusterAnnotation_3D-swift/Swift-Bridge-Header.h"; 709 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 710 | SWIFT_VERSION = 4.0; 711 | }; 712 | name = Release; 713 | }; 714 | 6A6C53BC1E08CF1800739D47 /* Debug */ = { 715 | isa = XCBuildConfiguration; 716 | buildSettings = { 717 | DEVELOPMENT_TEAM = YMJ372W38W; 718 | INFOPLIST_FILE = iOS_ClusterAnnotation_3DUITests/Info.plist; 719 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 720 | PRODUCT_BUNDLE_IDENTIFIER = "com.autonavi.iOS-ClusterAnnotation-3DUITests"; 721 | PRODUCT_NAME = "$(TARGET_NAME)"; 722 | PROVISIONING_PROFILE = "d723e77c-6c92-4e6a-98d7-8717d0b88b87"; 723 | PROVISIONING_PROFILE_SPECIFIER = openPlatform_development; 724 | TEST_TARGET_NAME = iOS_ClusterAnnotation_3D; 725 | }; 726 | name = Debug; 727 | }; 728 | 6A6C53BD1E08CF1800739D47 /* Release */ = { 729 | isa = XCBuildConfiguration; 730 | buildSettings = { 731 | DEVELOPMENT_TEAM = YMJ372W38W; 732 | INFOPLIST_FILE = iOS_ClusterAnnotation_3DUITests/Info.plist; 733 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 734 | PRODUCT_BUNDLE_IDENTIFIER = "com.autonavi.iOS-ClusterAnnotation-3DUITests"; 735 | PRODUCT_NAME = "$(TARGET_NAME)"; 736 | PROVISIONING_PROFILE = "d723e77c-6c92-4e6a-98d7-8717d0b88b87"; 737 | PROVISIONING_PROFILE_SPECIFIER = openPlatform_development; 738 | TEST_TARGET_NAME = iOS_ClusterAnnotation_3D; 739 | }; 740 | name = Release; 741 | }; 742 | /* End XCBuildConfiguration section */ 743 | 744 | /* Begin XCConfigurationList section */ 745 | 3AF7AD1E1E03C5D1001AE58A /* Build configuration list for PBXProject "iOS_ClusterAnnotation_3D" */ = { 746 | isa = XCConfigurationList; 747 | buildConfigurations = ( 748 | 3AF7AD381E03C5D1001AE58A /* Debug */, 749 | 3AF7AD391E03C5D1001AE58A /* Release */, 750 | ); 751 | defaultConfigurationIsVisible = 0; 752 | defaultConfigurationName = Release; 753 | }; 754 | 3AF7AD3A1E03C5D1001AE58A /* Build configuration list for PBXNativeTarget "iOS_ClusterAnnotation_3D" */ = { 755 | isa = XCConfigurationList; 756 | buildConfigurations = ( 757 | 3AF7AD3B1E03C5D1001AE58A /* Debug */, 758 | 3AF7AD3C1E03C5D1001AE58A /* Release */, 759 | ); 760 | defaultConfigurationIsVisible = 0; 761 | defaultConfigurationName = Release; 762 | }; 763 | 3AF7AD9C1E04234E001AE58A /* Build configuration list for PBXNativeTarget "iOS_ClusterAnnotation_3D-swift" */ = { 764 | isa = XCConfigurationList; 765 | buildConfigurations = ( 766 | 3AF7AD9D1E04234E001AE58A /* Debug */, 767 | 3AF7AD9E1E04234E001AE58A /* Release */, 768 | ); 769 | defaultConfigurationIsVisible = 0; 770 | defaultConfigurationName = Release; 771 | }; 772 | 6A6C53BE1E08CF1800739D47 /* Build configuration list for PBXNativeTarget "iOS_ClusterAnnotation_3DUITests" */ = { 773 | isa = XCConfigurationList; 774 | buildConfigurations = ( 775 | 6A6C53BC1E08CF1800739D47 /* Debug */, 776 | 6A6C53BD1E08CF1800739D47 /* Release */, 777 | ); 778 | defaultConfigurationIsVisible = 0; 779 | defaultConfigurationName = Release; 780 | }; 781 | /* End XCConfigurationList section */ 782 | }; 783 | rootObject = 3AF7AD1B1E03C5D1001AE58A /* Project object */; 784 | } 785 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D.xcodeproj/xcshareddata/xcschemes/iOS_ClusterAnnotation_3D-swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D.xcodeproj/xcshareddata/xcschemes/iOS_ClusterAnnotation_3D.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 87 | 93 | 94 | 95 | 96 | 98 | 99 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D.xcodeproj/xcshareddata/xcschemes/iOS_ClusterAnnotation_3DUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 41 | 42 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // iOS_3D_ClusterAnnotation 4 | // 5 | // Created by PC on 15/7/3. 6 | // Copyright (c) 2015年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // iOS_3D_ClusterAnnotation 4 | // 5 | // Created by PC on 15/7/3. 6 | // Copyright (c) 2015年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import 11 | #import "APIKey.h" 12 | #import "AnnotationClusterViewController.h" 13 | 14 | @interface AppDelegate () 15 | 16 | @property (strong, nonatomic) UIViewController *viewController; 17 | 18 | @end 19 | 20 | @implementation AppDelegate 21 | 22 | - (void)configureAPIKey 23 | { 24 | if ([APIKey length] == 0) 25 | { 26 | NSString *reason = [NSString stringWithFormat:@"apiKey为空,请检查key是否正确设置。"]; 27 | 28 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:reason delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 29 | 30 | [alert show]; 31 | } 32 | 33 | [AMapServices sharedServices].apiKey = (NSString *)APIKey; 34 | } 35 | 36 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 37 | 38 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 39 | 40 | [self configureAPIKey]; 41 | 42 | self.viewController = [[AnnotationClusterViewController alloc] init]; 43 | 44 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 45 | self.window.backgroundColor = [UIColor whiteColor]; 46 | [self.window makeKeyAndVisible]; 47 | 48 | return YES; 49 | } 50 | 51 | 52 | - (void)applicationWillResignActive:(UIApplication *)application { 53 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 54 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 55 | } 56 | 57 | 58 | - (void)applicationDidEnterBackground:(UIApplication *)application { 59 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 60 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 61 | } 62 | 63 | 64 | - (void)applicationWillEnterForeground:(UIApplication *)application { 65 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 66 | } 67 | 68 | 69 | - (void)applicationDidBecomeActive:(UIApplication *)application { 70 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 71 | } 72 | 73 | 74 | - (void)applicationWillTerminate:(UIApplication *)application { 75 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 76 | } 77 | 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-40x40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-60x60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "idiom" : "ios-marketing", 53 | "size" : "1024x1024", 54 | "scale" : "1x" 55 | } 56 | ], 57 | "info" : { 58 | "version" : 1, 59 | "author" : "xcode" 60 | } 61 | } -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amap-demo/iOS-cluster-marker/c6ab33524df86c7acc189287cdf247d1a21a2de8/iOS_ClusterAnnotation_3D/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Demo/Controller/AnnotationClusterViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AnnotationClusterViewController.h 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | 14 | @interface AnnotationClusterViewController : UIViewController 15 | 16 | @property (nonatomic, strong) MAMapView *mapView; 17 | @property (nonatomic, strong) AMapSearchAPI *search; 18 | @property (nonatomic, strong) UIButton *refreshButton; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Demo/Controller/AnnotationClusterViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AnnotationClusterViewController.m 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import "AnnotationClusterViewController.h" 10 | #import "PoiDetailViewController.h" 11 | 12 | #import "CoordinateQuadTree.h" 13 | #import "ClusterAnnotation.h" 14 | 15 | #import "ClusterAnnotationView.h" 16 | #import "ClusterTableViewCell.h" 17 | #import "CustomCalloutView.h" 18 | 19 | #define kCalloutViewMargin -12 20 | #define Button_Height 70.0 21 | 22 | @interface AnnotationClusterViewController () 23 | 24 | @property (nonatomic, strong) CoordinateQuadTree* coordinateQuadTree; 25 | 26 | @property (nonatomic, strong) CustomCalloutView *customCalloutView; 27 | 28 | @property (nonatomic, strong) NSMutableArray *selectedPoiArray; 29 | 30 | @property (nonatomic, assign) BOOL shouldRegionChangeReCalculate; 31 | 32 | @property (nonatomic, strong) AMapPOIKeywordsSearchRequest *currentRequest; 33 | @property (nonatomic, strong) dispatch_queue_t queue; 34 | 35 | @end 36 | 37 | @implementation AnnotationClusterViewController 38 | 39 | #pragma mark - update Annotation 40 | 41 | /* 更新annotation. */ 42 | - (void)updateMapViewAnnotationsWithAnnotations:(NSArray *)annotations 43 | { 44 | /* 用户滑动时,保留仍然可用的标注,去除屏幕外标注,添加新增区域的标注 */ 45 | NSMutableSet *before = [NSMutableSet setWithArray:self.mapView.annotations]; 46 | [before removeObject:[self.mapView userLocation]]; 47 | NSSet *after = [NSSet setWithArray:annotations]; 48 | 49 | /* 保留仍然位于屏幕内的annotation. */ 50 | NSMutableSet *toKeep = [NSMutableSet setWithSet:before]; 51 | [toKeep intersectSet:after]; 52 | 53 | /* 需要添加的annotation. */ 54 | NSMutableSet *toAdd = [NSMutableSet setWithSet:after]; 55 | [toAdd minusSet:toKeep]; 56 | 57 | /* 删除位于屏幕外的annotation. */ 58 | NSMutableSet *toRemove = [NSMutableSet setWithSet:before]; 59 | [toRemove minusSet:after]; 60 | 61 | /* 更新. */ 62 | dispatch_async(dispatch_get_main_queue(), ^{ 63 | [self.mapView addAnnotations:[toAdd allObjects]]; 64 | [self.mapView removeAnnotations:[toRemove allObjects]]; 65 | }); 66 | } 67 | 68 | - (void)addAnnotationsToMapView:(MAMapView *)mapView 69 | { 70 | @synchronized(self) 71 | { 72 | if (self.coordinateQuadTree.root == nil || !self.shouldRegionChangeReCalculate) 73 | { 74 | NSLog(@"tree is not ready."); 75 | return; 76 | } 77 | 78 | /* 根据当前zoomLevel和zoomScale 进行annotation聚合. */ 79 | MAMapRect visibleRect = self.mapView.visibleMapRect; 80 | double zoomScale = self.mapView.bounds.size.width / visibleRect.size.width; 81 | double zoomLevel = self.mapView.zoomLevel; 82 | 83 | /* 也可根据zoomLevel计算指定屏幕距离(以50像素为例)对应的实际距离 进行annotation聚合. */ 84 | /* 使用:NSArray *annotations = [weakSelf.coordinateQuadTree clusteredAnnotationsWithinMapRect:visibleRect withDistance:distance]; */ 85 | //double distance = 50.f * [self.mapView metersPerPointForZoomLevel:self.mapView.zoomLevel]; 86 | 87 | __weak typeof(self) weakSelf = self; 88 | dispatch_barrier_async(self.queue, ^{ 89 | 90 | NSArray *annotations = [weakSelf.coordinateQuadTree clusteredAnnotationsWithinMapRect:visibleRect 91 | withZoomScale:zoomScale 92 | andZoomLevel:zoomLevel]; 93 | dispatch_async(dispatch_get_main_queue(), ^{ 94 | /* 更新annotation. */ 95 | [weakSelf updateMapViewAnnotationsWithAnnotations:annotations]; 96 | }); 97 | }); 98 | } 99 | } 100 | 101 | #pragma mark - CustomCalloutViewTapDelegate 102 | 103 | - (void)didDetailButtonTapped:(NSInteger)index 104 | { 105 | PoiDetailViewController *detail = [[PoiDetailViewController alloc] init]; 106 | detail.poi = self.selectedPoiArray[index]; 107 | 108 | /* 进入POI详情页面. */ 109 | [self.navigationController pushViewController:detail animated:YES]; 110 | } 111 | 112 | #pragma mark - MAMapViewDelegate 113 | 114 | - (void)mapView:(MAMapView *)mapView didDeselectAnnotationView:(MAAnnotationView *)view 115 | { 116 | [self.selectedPoiArray removeAllObjects]; 117 | [self.customCalloutView dismissCalloutView]; 118 | self.customCalloutView.delegate = nil; 119 | } 120 | 121 | - (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view 122 | { 123 | ClusterAnnotation *annotation = (ClusterAnnotation *)view.annotation; 124 | for (AMapPOI *poi in annotation.pois) 125 | { 126 | [self.selectedPoiArray addObject:poi]; 127 | } 128 | 129 | [self.customCalloutView setPoiArray:self.selectedPoiArray]; 130 | self.customCalloutView.delegate = self; 131 | 132 | // 调整位置 133 | self.customCalloutView.center = CGPointMake(CGRectGetMidX(view.bounds), -CGRectGetMidY(self.customCalloutView.bounds) - CGRectGetMidY(view.bounds) - kCalloutViewMargin); 134 | 135 | [view addSubview:self.customCalloutView]; 136 | } 137 | 138 | - (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated 139 | { 140 | [self addAnnotationsToMapView:self.mapView]; 141 | } 142 | 143 | - (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id)annotation 144 | { 145 | if ([annotation isKindOfClass:[ClusterAnnotation class]]) 146 | { 147 | /* dequeue重用annotationView. */ 148 | static NSString *const AnnotatioViewReuseID = @"AnnotatioViewReuseID"; 149 | 150 | ClusterAnnotationView *annotationView = (ClusterAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotatioViewReuseID]; 151 | 152 | if (!annotationView) 153 | { 154 | annotationView = [[ClusterAnnotationView alloc] initWithAnnotation:annotation 155 | reuseIdentifier:AnnotatioViewReuseID]; 156 | } 157 | 158 | /* 设置annotationView的属性. */ 159 | annotationView.annotation = annotation; 160 | annotationView.count = [(ClusterAnnotation *)annotation count]; 161 | 162 | /* 不弹出原生annotation */ 163 | annotationView.canShowCallout = NO; 164 | 165 | return annotationView; 166 | } 167 | 168 | return nil; 169 | } 170 | 171 | #pragma mark - SearchPOI 172 | 173 | /* 搜索POI. */ 174 | - (void)searchPoiWithKeyword:(NSString *)keyword 175 | { 176 | AMapPOIKeywordsSearchRequest *request = [[AMapPOIKeywordsSearchRequest alloc] init]; 177 | 178 | request.keywords = keyword; 179 | request.city = @"010"; 180 | request.requireExtension = YES; 181 | 182 | self.currentRequest = request; 183 | [self.search AMapPOIKeywordsSearch:request]; 184 | } 185 | 186 | /* POI 搜索回调. */ 187 | 188 | - (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response 189 | { 190 | if (response.pois.count == 0) 191 | { 192 | return; 193 | } 194 | 195 | // 只处理最新的请求 196 | if (request != self.currentRequest) 197 | { 198 | return; 199 | } 200 | 201 | @synchronized(self) 202 | { 203 | self.shouldRegionChangeReCalculate = NO; 204 | 205 | // 清理 206 | [self.selectedPoiArray removeAllObjects]; 207 | [self.customCalloutView dismissCalloutView]; 208 | 209 | NSMutableArray *annosToRemove = [NSMutableArray arrayWithArray:self.mapView.annotations]; 210 | [annosToRemove removeObject:self.mapView.userLocation]; 211 | [self.mapView removeAnnotations:annosToRemove]; 212 | 213 | __weak typeof(self) weakSelf = self; 214 | dispatch_async(self.queue, ^{ 215 | /* 建立四叉树. */ 216 | [weakSelf.coordinateQuadTree buildTreeWithPOIs:response.pois]; 217 | weakSelf.shouldRegionChangeReCalculate = YES; 218 | 219 | dispatch_async(dispatch_get_main_queue(), ^{ 220 | [weakSelf addAnnotationsToMapView:weakSelf.mapView]; 221 | }); 222 | }); 223 | } 224 | 225 | } 226 | 227 | #pragma mark - Refresh Button Action 228 | 229 | - (void)refreshAction:(UIButton *)button 230 | { 231 | [self searchPoiWithKeyword:@"Apple"]; 232 | } 233 | 234 | #pragma mark - Life Cycle 235 | 236 | - (id)init 237 | { 238 | if (self = [super init]) 239 | { 240 | self.coordinateQuadTree = [[CoordinateQuadTree alloc] init]; 241 | 242 | self.selectedPoiArray = [[NSMutableArray alloc] init]; 243 | 244 | self.customCalloutView = [[CustomCalloutView alloc] init]; 245 | 246 | self.queue = dispatch_queue_create("quadQueue", DISPATCH_QUEUE_SERIAL); 247 | } 248 | 249 | return self; 250 | } 251 | 252 | - (void)viewDidLoad 253 | { 254 | [super viewDidLoad]; 255 | 256 | [self setTitle:@"Cluster Annotations"]; 257 | 258 | [self initMapView]; 259 | 260 | [self initSearch]; 261 | 262 | [self initRefreshButton]; 263 | 264 | _shouldRegionChangeReCalculate = NO; 265 | 266 | [self searchPoiWithKeyword:@"Apple"]; 267 | } 268 | 269 | - (void)dealloc 270 | { 271 | [self.coordinateQuadTree clean]; 272 | } 273 | 274 | - (void)initMapView 275 | { 276 | if (self.mapView == nil) 277 | { 278 | self.mapView = [[MAMapView alloc] initWithFrame:self.view.bounds]; 279 | self.mapView.allowsAnnotationViewSorting = NO; 280 | self.mapView.delegate = self; 281 | } 282 | 283 | self.mapView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - Button_Height); 284 | 285 | [self.view addSubview:self.mapView]; 286 | 287 | self.mapView.visibleMapRect = MAMapRectMake(220880104, 101476980, 272496, 466656); 288 | } 289 | 290 | - (void)initSearch 291 | { 292 | self.search = [[AMapSearchAPI alloc] init]; 293 | self.search.delegate = self; 294 | } 295 | 296 | - (void)initRefreshButton 297 | { 298 | self.refreshButton = [UIButton buttonWithType:UIButtonTypeCustom]; 299 | [self.refreshButton setFrame:CGRectMake(0, _mapView.frame.origin.y + _mapView.frame.size.height, _mapView.frame.size.width, Button_Height)]; 300 | [self.refreshButton setTitle:@"重新加载数据" forState:UIControlStateNormal]; 301 | [self.refreshButton setTitleColor:[UIColor purpleColor] forState:UIControlStateNormal]; 302 | 303 | [self.refreshButton addTarget:self action:@selector(refreshAction:) forControlEvents:UIControlEventTouchUpInside]; 304 | 305 | [self.view addSubview:self.refreshButton]; 306 | } 307 | 308 | @end 309 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Demo/Controller/PoiDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PoiDetailViewController.h 3 | // SearchV3Demo 4 | // 5 | // Created by songjian on 13-8-16. 6 | // Copyright (c) 2013年 songjian. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface PoiDetailViewController : UIViewController 13 | 14 | @property (nonatomic, strong) AMapPOI *poi; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Demo/Controller/PoiDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PoiDetailViewController.m 3 | // SearchV3Demo 4 | // 5 | // Created by songjian on 13-8-16. 6 | // Copyright (c) 2013年 songjian. All rights reserved. 7 | // 8 | 9 | #import "PoiDetailViewController.h" 10 | 11 | #define TemporaryNotOpened @"暂未开通" 12 | 13 | @interface PoiDetailViewController () 14 | 15 | @property (nonatomic, strong) UITableView *tableView; 16 | 17 | @end 18 | 19 | @implementation PoiDetailViewController 20 | @synthesize poi = _poi; 21 | @synthesize tableView = _tableView; 22 | 23 | #pragma mark - Utility 24 | 25 | - (NSString *)titleForIndexPath:(NSIndexPath *)indexPath 26 | { 27 | NSString *title = nil; 28 | 29 | if (indexPath.section == 0) 30 | { 31 | switch (indexPath.row) 32 | { 33 | case 0 : title = @"POI全局唯一ID"; break; 34 | case 1 : title = @"名称"; break; 35 | case 2 : title = @"兴趣点类型"; break; 36 | case 3 : title = @"经纬度"; break; 37 | case 4 : title = @"地址"; break; 38 | case 5 : title = @"电话"; break; 39 | default: title = @"距中心点距离"; break; 40 | } 41 | } 42 | else 43 | { 44 | switch (indexPath.row) 45 | { 46 | case 0 : title = @"邮编"; break; 47 | case 1 : title = @"网址"; break; 48 | case 2 : title = @"电子邮件"; break; 49 | case 3 : title = @"省(省编码)"; break; 50 | case 4 : title = @"市(市编码)"; break; 51 | case 5 : title = @"区域(区域编码)"; break; 52 | case 6 : title = @"地理格ID"; break; 53 | case 7 : title = @"导航点ID"; break; 54 | case 8 : title = @"入口经纬度"; break; 55 | case 9 : title = @"出口经纬度"; break; 56 | case 10 : title = @"权重"; break; 57 | case 11 : title = @"匹配"; break; 58 | case 12 : title = @"推荐标识"; break; 59 | case 13 : title = @"时间戳"; break; 60 | case 14 : title = @"方向"; break; 61 | case 15 : title = @"是否有室内地图"; break; 62 | case 16 : title = @"室内地图来源"; break; 63 | 64 | default : break; 65 | } 66 | } 67 | 68 | return title; 69 | } 70 | 71 | - (NSString *)subTitleForIndexPath:(NSIndexPath *)indexPath 72 | { 73 | NSString *subTitle = nil; 74 | 75 | if (indexPath.section == 0) 76 | { 77 | switch (indexPath.row) 78 | { 79 | case 0 : subTitle = self.poi.uid; break; 80 | case 1 : subTitle = self.poi.name; break; 81 | case 2 : subTitle = self.poi.type; break; 82 | case 3 : subTitle = [self.poi.location description]; break; 83 | case 4 : subTitle = self.poi.address; break; 84 | case 5 : subTitle = self.poi.tel; break; 85 | default: subTitle = [NSString stringWithFormat:@"%ld(米)", (long)self.poi.distance]; break; 86 | 87 | } 88 | } 89 | else 90 | { 91 | switch (indexPath.row) 92 | { 93 | case 0 : subTitle = self.poi.postcode; break; 94 | case 1 : subTitle = self.poi.website; break; 95 | case 2 : subTitle = self.poi.email; break; 96 | case 3 : subTitle = [NSString stringWithFormat:@"%@(%@)", self.poi.province, self.poi.pcode]; break; 97 | case 4 : subTitle = [NSString stringWithFormat:@"%@(%@)", self.poi.city, self.poi.citycode]; break; 98 | case 5 : subTitle = [NSString stringWithFormat:@"%@(%@)", self.poi.district, self.poi.adcode]; break; 99 | case 6 : subTitle = TemporaryNotOpened; break; 100 | case 7 : subTitle = TemporaryNotOpened; break; 101 | case 8 : subTitle = [self.poi.enterLocation description]; break; 102 | case 9 : subTitle = [self.poi.exitLocation description]; break; 103 | case 10 : subTitle = TemporaryNotOpened; break; 104 | case 11 : subTitle = TemporaryNotOpened; break; 105 | case 12 : subTitle = TemporaryNotOpened; break; 106 | case 13 : subTitle = TemporaryNotOpened; break; 107 | case 14 : subTitle = self.poi.direction; break; 108 | case 15 : subTitle = [NSString stringWithFormat:@"%d", self.poi.hasIndoorMap]; break; 109 | default : break; 110 | } 111 | } 112 | 113 | return subTitle; 114 | } 115 | 116 | #pragma mark - UITableViewDataSource 117 | 118 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 119 | { 120 | return 1; 121 | } 122 | 123 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 124 | { 125 | return section == 0 ? 7 : 17; 126 | } 127 | 128 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 129 | { 130 | static NSString *poiDetailCellIdentifier = @"poiDetailCellIdentifier"; 131 | 132 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:poiDetailCellIdentifier]; 133 | 134 | if (cell == nil) 135 | { 136 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:poiDetailCellIdentifier]; 137 | } 138 | 139 | cell.textLabel.text = [self titleForIndexPath:indexPath]; 140 | cell.detailTextLabel.text = [self subTitleForIndexPath:indexPath]; 141 | cell.accessoryType = UITableViewCellAccessoryNone; 142 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 143 | 144 | return cell; 145 | } 146 | 147 | #pragma mark - Initialization 148 | 149 | - (void)initTableView 150 | { 151 | self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 152 | self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 153 | self.tableView.delegate = self; 154 | self.tableView.dataSource = self; 155 | 156 | [self.view addSubview:self.tableView]; 157 | } 158 | 159 | - (void)initTitle:(NSString *)title 160 | { 161 | UILabel *titleLabel = [[UILabel alloc] init]; 162 | 163 | titleLabel.backgroundColor = [UIColor clearColor]; 164 | titleLabel.textColor = [UIColor blackColor]; 165 | titleLabel.text = title; 166 | [titleLabel sizeToFit]; 167 | 168 | self.navigationItem.titleView = titleLabel; 169 | } 170 | 171 | #pragma mark - Life Cycle 172 | 173 | - (void)viewDidLoad 174 | { 175 | [super viewDidLoad]; 176 | 177 | [self initTitle:@"POI信息 (AMapPOI)"]; 178 | 179 | [self initTableView]; 180 | } 181 | 182 | @end 183 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Model/ClusterAnnotation.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClusterAnnotation.h 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface ClusterAnnotation : NSObject 14 | 15 | @property (assign, nonatomic) CLLocationCoordinate2D coordinate; //poi的平均位置 16 | @property (assign, nonatomic) NSInteger count; 17 | @property (nonatomic, strong) NSMutableArray *pois; 18 | @property (nonatomic, copy) NSString *title; 19 | @property (nonatomic, copy) NSString *subtitle; 20 | 21 | 22 | - (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate count:(NSInteger)count; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Model/ClusterAnnotation.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClusterAnnotation.m 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import "ClusterAnnotation.h" 10 | 11 | @implementation ClusterAnnotation 12 | 13 | #pragma mark - compare 14 | 15 | - (NSUInteger)hash 16 | { 17 | NSString *toHash = [NSString stringWithFormat:@"%.5F%.5F%ld", self.coordinate.latitude, self.coordinate.longitude, (long)self.count]; 18 | return [toHash hash]; 19 | } 20 | 21 | - (BOOL)isEqual:(id)object 22 | { 23 | return [self hash] == [object hash]; 24 | } 25 | 26 | #pragma mark - Life Cycle 27 | 28 | - (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate count:(NSInteger)count 29 | { 30 | self = [super init]; 31 | if (self) 32 | { 33 | _coordinate = coordinate; 34 | _count = count; 35 | _pois = [NSMutableArray arrayWithCapacity:count]; 36 | } 37 | return self; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Model/CoordinateQuadTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoordinateQuadTree.h 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "QuadTree.h" 12 | 13 | @interface CoordinateQuadTree : NSObject 14 | 15 | @property (nonatomic, assign) QuadTreeNode * root; 16 | 17 | /// 这里对poi对象的内存管理被四叉树接管了,当clean的时候会释放,外部有引用poi的地方必须再clean前清理。 18 | - (void)buildTreeWithPOIs:(NSArray *)pois; 19 | - (void)clean; 20 | 21 | - (NSArray *)clusteredAnnotationsWithinMapRect:(MAMapRect)rect withZoomScale:(double)zoomScale andZoomLevel:(double)zoomLevel; 22 | - (NSArray *)clusteredAnnotationsWithinMapRect:(MAMapRect)rect withDistance:(double)distance; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Model/CoordinateQuadTree.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoordinateQuadTree.m 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "CoordinateQuadTree.h" 12 | #import "ClusterAnnotation.h" 13 | 14 | QuadTreeNodeData QuadTreeNodeDataForAMapPOI(AMapPOI* poi) 15 | { 16 | return QuadTreeNodeDataMake(poi.location.latitude, poi.location.longitude, (__bridge_retained void *)(poi)); 17 | } 18 | 19 | BoundingBox BoundingBoxForMapRect(MAMapRect mapRect) 20 | { 21 | CLLocationCoordinate2D topLeft = MACoordinateForMapPoint(mapRect.origin); 22 | CLLocationCoordinate2D botRight = MACoordinateForMapPoint(MAMapPointMake(MAMapRectGetMaxX(mapRect), MAMapRectGetMaxY(mapRect))); 23 | 24 | CLLocationDegrees minLat = botRight.latitude; 25 | CLLocationDegrees maxLat = topLeft.latitude; 26 | 27 | CLLocationDegrees minLon = topLeft.longitude; 28 | CLLocationDegrees maxLon = botRight.longitude; 29 | 30 | return BoundingBoxMake(minLat, minLon, maxLat, maxLon); 31 | } 32 | 33 | float CellSizeForZoomLevel(double zoomLevel) 34 | { 35 | /*zoomLevel越大,cellSize越小. */ 36 | if (zoomLevel < 13.0) 37 | { 38 | return 64; 39 | } 40 | else if (zoomLevel <15.0) 41 | { 42 | return 32; 43 | } 44 | else if (zoomLevel <18.0) 45 | { 46 | return 16; 47 | } 48 | else if (zoomLevel < 20.0) 49 | { 50 | return 8; 51 | } 52 | 53 | return 64; 54 | } 55 | 56 | BoundingBox quadTreeNodeDataArrayForPOIs(QuadTreeNodeData *dataArray, NSArray * pois) 57 | { 58 | CLLocationDegrees minX = ((AMapPOI *)pois[0]).location.latitude; 59 | CLLocationDegrees maxX = ((AMapPOI *)pois[0]).location.latitude; 60 | 61 | CLLocationDegrees minY = ((AMapPOI *)pois[0]).location.longitude; 62 | CLLocationDegrees maxY = ((AMapPOI *)pois[0]).location.longitude; 63 | 64 | for (NSInteger i = 0; i < [pois count]; i++) 65 | { 66 | dataArray[i] = QuadTreeNodeDataForAMapPOI(pois[i]); 67 | 68 | if (dataArray[i].x < minX) 69 | { 70 | minX = dataArray[i].x; 71 | } 72 | 73 | if (dataArray[i].x > maxX) 74 | { 75 | maxX = dataArray[i].x; 76 | } 77 | 78 | if (dataArray[i].y < minY) 79 | { 80 | minY = dataArray[i].y; 81 | } 82 | 83 | if (dataArray[i].y > maxY) 84 | { 85 | maxY = dataArray[i].y; 86 | } 87 | } 88 | 89 | return BoundingBoxMake(minX, minY, maxX, maxY); 90 | } 91 | 92 | #pragma mark - 93 | 94 | @implementation CoordinateQuadTree 95 | 96 | #pragma mark Utility 97 | 98 | - (NSArray *)getAnnotationsWithoutClusteredInMapRect:(MAMapRect)rect 99 | { 100 | __block NSMutableArray *clusteredAnnotations = [[NSMutableArray alloc] init]; 101 | QuadTreeGatherDataInRange(self.root, BoundingBoxForMapRect(rect), ^(QuadTreeNodeData data) { 102 | AMapPOI *aPoi = (__bridge AMapPOI *)data.data; 103 | 104 | CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(aPoi.location.latitude, aPoi.location.longitude); 105 | ClusterAnnotation *annotation = [[ClusterAnnotation alloc] initWithCoordinate:coordinate count:1]; 106 | annotation.pois = @[aPoi].mutableCopy; 107 | 108 | [clusteredAnnotations addObject:annotation]; 109 | }); 110 | 111 | return clusteredAnnotations; 112 | } 113 | 114 | - (NSArray *)clusteredAnnotationsWithinMapRect:(MAMapRect)rect withZoomScale:(double)zoomScale andZoomLevel:(double)zoomLevel 115 | { 116 | //满足特定zoomLevel时不产生聚合效果(这里取地图的最大zoomLevel,效果为地图达到最大zoomLevel时,annotation全部展开,无聚合效果) 117 | if (zoomLevel >= 19.0) 118 | { 119 | return [self getAnnotationsWithoutClusteredInMapRect:rect]; 120 | } 121 | 122 | double CellSize = CellSizeForZoomLevel(zoomLevel); 123 | double scaleFactor = zoomScale / CellSize; 124 | 125 | NSInteger minX = floor(MAMapRectGetMinX(rect) * scaleFactor); 126 | NSInteger maxX = floor(MAMapRectGetMaxX(rect) * scaleFactor); 127 | NSInteger minY = floor(MAMapRectGetMinY(rect) * scaleFactor); 128 | NSInteger maxY = floor(MAMapRectGetMaxY(rect) * scaleFactor); 129 | 130 | NSMutableArray *clusteredAnnotations = [[NSMutableArray alloc] init]; 131 | for (NSInteger x = minX; x <= maxX; x++) 132 | { 133 | for (NSInteger y = minY; y <= maxY; y++) 134 | { 135 | MAMapRect mapRect = MAMapRectMake(x / scaleFactor, y / scaleFactor, 1.0 / scaleFactor, 1.0 / scaleFactor); 136 | 137 | __block double totalX = 0; 138 | __block double totalY = 0; 139 | __block int count = 0; 140 | 141 | NSMutableArray *pois = [[NSMutableArray alloc] init]; 142 | 143 | /* 查询区域内数据的个数. */ 144 | QuadTreeGatherDataInRange(self.root, BoundingBoxForMapRect(mapRect), ^(QuadTreeNodeData data) 145 | { 146 | totalX += data.x; 147 | totalY += data.y; 148 | count++; 149 | 150 | [pois addObject:(__bridge AMapPOI *)data.data]; 151 | }); 152 | 153 | /* 若区域内仅有一个数据. */ 154 | if (count == 1) 155 | { 156 | CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(totalX, totalY); 157 | ClusterAnnotation *annotation = [[ClusterAnnotation alloc] initWithCoordinate:coordinate count:count]; 158 | annotation.pois = pois; 159 | 160 | [clusteredAnnotations addObject:annotation]; 161 | } 162 | 163 | /* 若区域内有多个数据 按数据的中心位置画点. */ 164 | if (count > 1) 165 | { 166 | CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(totalX / count, totalY / count); 167 | ClusterAnnotation *annotation = [[ClusterAnnotation alloc] initWithCoordinate:coordinate count:count]; 168 | annotation.pois = pois; 169 | 170 | [clusteredAnnotations addObject:annotation]; 171 | } 172 | } 173 | } 174 | 175 | return [NSArray arrayWithArray:clusteredAnnotations]; 176 | } 177 | 178 | #pragma mark - cluster by distance 179 | 180 | ///按照annotation.coordinate之间的距离进行聚合 181 | - (NSArray *)clusteredAnnotationsWithinMapRect:(MAMapRect)rect withDistance:(double)distance { 182 | __block NSMutableArray *allAnnotations = [[NSMutableArray alloc] init]; 183 | QuadTreeGatherDataInRange(self.root, BoundingBoxForMapRect(rect), ^(QuadTreeNodeData data) { 184 | [allAnnotations addObject:(__bridge AMapPOI *)data.data]; 185 | }); 186 | 187 | NSMutableArray *clusteredAnnotations = [[NSMutableArray alloc] init]; 188 | for (AMapPOI *aAnnotation in allAnnotations) { 189 | CLLocationCoordinate2D resultCoor = CLLocationCoordinate2DMake(aAnnotation.location.latitude, aAnnotation.location.longitude); 190 | 191 | ClusterAnnotation *cluster = [self getClusterForAnnotation:aAnnotation inClusteredAnnotations:clusteredAnnotations withDistance:distance]; 192 | if (cluster == nil) { 193 | ClusterAnnotation *aResult = [[ClusterAnnotation alloc] initWithCoordinate:resultCoor count:1]; 194 | aResult.pois = @[aAnnotation].mutableCopy; 195 | 196 | [clusteredAnnotations addObject:aResult]; 197 | } else { 198 | double totalX = cluster.coordinate.latitude * cluster.count + resultCoor.latitude; 199 | double totalY = cluster.coordinate.longitude * cluster.count + resultCoor.longitude; 200 | NSInteger totalCount = cluster.count + 1; 201 | 202 | cluster.count = totalCount; 203 | cluster.coordinate = CLLocationCoordinate2DMake(totalX / totalCount, totalY / totalCount); 204 | [cluster.pois addObject:aAnnotation]; 205 | } 206 | } 207 | 208 | return clusteredAnnotations; 209 | } 210 | 211 | - (ClusterAnnotation *)getClusterForAnnotation:(AMapPOI *)annotation inClusteredAnnotations:(NSArray *)clusteredAnnotations withDistance:(double)distance { 212 | if ([clusteredAnnotations count] <= 0 || annotation == nil) { 213 | return nil; 214 | } 215 | 216 | CLLocation *annotationLocation = [[CLLocation alloc] initWithLatitude:annotation.location.latitude longitude:annotation.location.longitude]; 217 | for (ClusterAnnotation *aCluster in clusteredAnnotations) { 218 | CLLocation *clusterLocation = [[CLLocation alloc] initWithLatitude:aCluster.coordinate.latitude longitude:aCluster.coordinate.longitude]; 219 | double dis = [clusterLocation distanceFromLocation:annotationLocation]; 220 | if (dis < distance) { 221 | return aCluster; 222 | } 223 | } 224 | 225 | return nil; 226 | } 227 | 228 | #pragma mark Initilization 229 | 230 | - (void)buildTreeWithPOIs:(NSArray *)pois 231 | { 232 | QuadTreeNodeData *dataArray = malloc(sizeof(QuadTreeNodeData) * [pois count]); 233 | 234 | BoundingBox maxBounding = quadTreeNodeDataArrayForPOIs(dataArray, pois); 235 | 236 | /*若已有四叉树,清空.*/ 237 | [self clean]; 238 | 239 | NSLog(@"build tree."); 240 | /*建立四叉树索引. */ 241 | self.root = QuadTreeBuildWithData(dataArray, [pois count], maxBounding, 4); 242 | 243 | free(dataArray); 244 | } 245 | 246 | #pragma mark Life Cycle 247 | 248 | - (void)clean 249 | { 250 | if (self.root) 251 | { 252 | NSLog(@"free tree."); 253 | FreeQuadTreeNode(self.root); 254 | } 255 | 256 | } 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Model/QuadTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // QuadTree.h 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef struct QuadTreeNodeData 12 | { 13 | double x; 14 | double y; 15 | void * data; 16 | } QuadTreeNodeData; 17 | QuadTreeNodeData QuadTreeNodeDataMake(double x, double y, void* data); 18 | 19 | typedef struct BoundingBox 20 | { 21 | double x0; double y0; 22 | double xm; double ym; 23 | } BoundingBox; 24 | BoundingBox BoundingBoxMake(double x0, double y0, double xm, double ym); 25 | 26 | typedef struct QuadTreeNode 27 | { 28 | struct QuadTreeNode * northEast; 29 | struct QuadTreeNode * northWest; 30 | struct QuadTreeNode * southEast; 31 | struct QuadTreeNode * southWest; 32 | 33 | BoundingBox boundingBox; 34 | int bucketCapacity; 35 | QuadTreeNodeData * points; 36 | int pointsCount; 37 | } QuadTreeNode; 38 | QuadTreeNode* QuadTreeNodeMake(BoundingBox boundingBox, int bucketCapacity); 39 | 40 | /*! 41 | 建立四叉树 42 | @param data 用于建树的节点数据指针 43 | @param count 节点数据的个数 44 | @param boundingBox 四叉树覆盖的范围 45 | @param capacity 单节点能容纳的节点数据个数 46 | @return 四叉树的根节点 47 | */ 48 | QuadTreeNode* QuadTreeBuildWithData(QuadTreeNodeData *data, NSUInteger count, BoundingBox boundingBox, int capacity); 49 | 50 | /*! 51 | 在四叉树中插入节点数据 52 | @param node 插入的节点位置 53 | @param data 需要插入的节点数据 54 | @return 成功插入返回true,否则false 55 | */ 56 | bool QuadTreeNodeInsertData(QuadTreeNode* node, QuadTreeNodeData data); 57 | 58 | /*! 59 | 拆分节点 60 | @param node 输入需拆分的节点 61 | */ 62 | void QuadTreeNodeSubdivide(QuadTreeNode* node); 63 | 64 | /*! 65 | 判断节点数据是否在box范围内 66 | @param box box范围 67 | @param data 节点数据 68 | @return 若data在box内,返回true,否则false 69 | */ 70 | bool BoundingBoxContainsData(BoundingBox box, QuadTreeNodeData data); 71 | 72 | /*! 73 | 判断两box是否相交 74 | */ 75 | bool BoundingBoxIntersectsBoundingBox(BoundingBox b1, BoundingBox b2); 76 | 77 | typedef void(^DataReturnBlock)(QuadTreeNodeData data); 78 | void QuadTreeGatherDataInRange(QuadTreeNode* node, BoundingBox range, DataReturnBlock block); 79 | 80 | /*! 81 | 清空四叉树 82 | @param node 四叉数根节点 83 | */ 84 | void FreeQuadTreeNode(QuadTreeNode* node); 85 | 86 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/Model/QuadTree.m: -------------------------------------------------------------------------------- 1 | // 2 | // QuadTree.m 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import "QuadTree.h" 10 | 11 | #pragma mark - Constructors 12 | 13 | QuadTreeNodeData QuadTreeNodeDataMake(double x, double y, void* data) 14 | { 15 | QuadTreeNodeData d; d.x = x; d.y = y; d.data = data; 16 | return d; 17 | } 18 | 19 | BoundingBox BoundingBoxMake(double x0, double y0, double xm, double ym) 20 | { 21 | BoundingBox bb; bb.x0 = x0; bb.y0 = y0; bb.xm = xm; bb.ym = ym; 22 | return bb; 23 | } 24 | 25 | QuadTreeNode* QuadTreeNodeMake(BoundingBox boundary, int bucketCapacity) 26 | { 27 | QuadTreeNode* node = malloc(sizeof(QuadTreeNode)); 28 | node->northWest = NULL; 29 | node->northEast = NULL; 30 | node->southWest = NULL; 31 | node->southEast = NULL; 32 | 33 | node->boundingBox = boundary; 34 | node->bucketCapacity = bucketCapacity; 35 | node->pointsCount = 0; 36 | node->points = malloc(sizeof(QuadTreeNodeData) * bucketCapacity); 37 | 38 | return node; 39 | } 40 | 41 | #pragma mark - Bounding Box Functions 42 | 43 | bool BoundingBoxContainsData(BoundingBox box, QuadTreeNodeData data) 44 | { 45 | bool containsX = box.x0 <= data.x && data.x <= box.xm; 46 | bool containsY = box.y0 <= data.y && data.y <= box.ym; 47 | 48 | return containsX && containsY; 49 | } 50 | 51 | bool BoundingBoxIntersectsBoundingBox(BoundingBox b1, BoundingBox b2) 52 | { 53 | return (b1.x0 <= b2.xm && b1.xm >= b2.x0 && b1.y0 <= b2.ym && b1.ym >= b2.y0); 54 | } 55 | 56 | #pragma mark - Quad Tree Functions 57 | 58 | void QuadTreeNodeSubdivide(QuadTreeNode* node) 59 | { 60 | BoundingBox box = node->boundingBox; 61 | 62 | double xMid = (box.xm + box.x0) / 2.0; 63 | double yMid = (box.ym + box.y0) / 2.0; 64 | 65 | BoundingBox northWest = BoundingBoxMake(box.x0, box.y0, xMid, yMid); 66 | node->northWest = QuadTreeNodeMake(northWest, node->bucketCapacity); 67 | 68 | BoundingBox northEast = BoundingBoxMake(xMid, box.y0, box.xm, yMid); 69 | node->northEast = QuadTreeNodeMake(northEast, node->bucketCapacity); 70 | 71 | BoundingBox southWest = BoundingBoxMake(box.x0, yMid, xMid, box.ym); 72 | node->southWest = QuadTreeNodeMake(southWest, node->bucketCapacity); 73 | 74 | BoundingBox southEast = BoundingBoxMake(xMid, yMid, box.xm, box.ym); 75 | node->southEast = QuadTreeNodeMake(southEast, node->bucketCapacity); 76 | } 77 | 78 | bool QuadTreeNodeInsertData(QuadTreeNode* node, QuadTreeNodeData data) 79 | { 80 | if (!BoundingBoxContainsData(node->boundingBox, data)) 81 | { 82 | return false; 83 | } 84 | 85 | if (node->pointsCount < node->bucketCapacity) 86 | { 87 | node->points[node->pointsCount++] = data; 88 | return true; 89 | } 90 | 91 | /* 若节点容量已满,且该节点为叶子节点,则向下扩展. */ 92 | if (node->northWest == NULL) 93 | { 94 | QuadTreeNodeSubdivide(node); 95 | } 96 | 97 | if (QuadTreeNodeInsertData(node->northWest, data)) return true; 98 | if (QuadTreeNodeInsertData(node->northEast, data)) return true; 99 | if (QuadTreeNodeInsertData(node->southWest, data)) return true; 100 | if (QuadTreeNodeInsertData(node->southEast, data)) return true; 101 | 102 | return false; 103 | } 104 | 105 | QuadTreeNode* QuadTreeBuildWithData(QuadTreeNodeData *data, NSUInteger count, BoundingBox boundingBox, int capacity) 106 | { 107 | 108 | QuadTreeNode* root = QuadTreeNodeMake(boundingBox, capacity); 109 | for (int i = 0; i < count; i++) 110 | { 111 | QuadTreeNodeInsertData(root, data[i]); 112 | } 113 | 114 | return root; 115 | } 116 | 117 | void QuadTreeGatherDataInRange(QuadTreeNode* node, BoundingBox range, DataReturnBlock block) 118 | { 119 | /* 若节点的覆盖范围与range不相交,则返回. */ 120 | if (!BoundingBoxIntersectsBoundingBox(node->boundingBox, range)) 121 | { 122 | return; 123 | } 124 | 125 | 126 | for (int i = 0; i < node->pointsCount; i++) 127 | { 128 | /* 若节点数据在range内,则调用block记录. */ 129 | if (BoundingBoxContainsData(range, node->points[i])) 130 | { 131 | block(node->points[i]); 132 | } 133 | } 134 | 135 | /* 若已是叶子节点,返回. */ 136 | if (node->northWest == NULL) 137 | { 138 | return; 139 | } 140 | 141 | /* 不是叶子节点,继续向下查找. */ 142 | QuadTreeGatherDataInRange(node->northWest, range, block); 143 | QuadTreeGatherDataInRange(node->northEast, range, block); 144 | QuadTreeGatherDataInRange(node->southWest, range, block); 145 | QuadTreeGatherDataInRange(node->southEast, range, block); 146 | 147 | } 148 | 149 | void FreeQuadTreeNode(QuadTreeNode* node) 150 | { 151 | if (node->northWest != NULL) FreeQuadTreeNode(node->northWest); 152 | if (node->northEast != NULL) FreeQuadTreeNode(node->northEast); 153 | if (node->southWest != NULL) FreeQuadTreeNode(node->southWest); 154 | if (node->southEast != NULL) FreeQuadTreeNode(node->southEast); 155 | 156 | for (int i=0; i < node->pointsCount; i++) 157 | { 158 | // free(node->points[i].data); 159 | CFRelease(node->points[i].data); 160 | } 161 | free(node->points); 162 | free(node); 163 | } -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/View/ClusterAnnotationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClusterAnnotationView.h 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface ClusterAnnotationView : MAAnnotationView 14 | 15 | @property (nonatomic, assign) NSUInteger count; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/View/ClusterAnnotationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClusterAnnotationView.m 3 | // officialDemo2D 4 | // 5 | // Created by yi chen on 14-5-15. 6 | // Copyright (c) 2014年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import "ClusterAnnotationView.h" 10 | #import "ClusterAnnotation.h" 11 | 12 | 13 | static CGFloat const ScaleFactorAlpha = 0.3; 14 | static CGFloat const ScaleFactorBeta = 0.4; 15 | 16 | /* 返回rect的中心. */ 17 | CGPoint RectCenter(CGRect rect) 18 | { 19 | return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)); 20 | } 21 | 22 | /* 返回中心为center,尺寸为rect.size的rect. */ 23 | CGRect CenterRect(CGRect rect, CGPoint center) 24 | { 25 | CGRect r = CGRectMake(center.x - rect.size.width/2.0, 26 | center.y - rect.size.height/2.0, 27 | rect.size.width, 28 | rect.size.height); 29 | return r; 30 | } 31 | 32 | /* 根据count计算annotation的scale. */ 33 | CGFloat ScaledValueForValue(CGFloat value) 34 | { 35 | return 1.0 / (1.0 + expf(-1 * ScaleFactorAlpha * powf(value, ScaleFactorBeta))); 36 | } 37 | 38 | #pragma mark - 39 | 40 | @interface ClusterAnnotationView () 41 | 42 | @property (nonatomic, strong) UILabel *countLabel; 43 | 44 | @end 45 | 46 | @implementation ClusterAnnotationView 47 | 48 | #pragma mark Initialization 49 | 50 | - (id)initWithAnnotation:(id)annotation reuseIdentifier:(NSString *)reuseIdentifier 51 | { 52 | self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]; 53 | if (self) 54 | { 55 | self.backgroundColor = [UIColor clearColor]; 56 | [self setupLabel]; 57 | [self setCount:1]; 58 | } 59 | 60 | return self; 61 | } 62 | 63 | #pragma mark Utility 64 | 65 | - (void)setupLabel 66 | { 67 | _countLabel = [[UILabel alloc] initWithFrame:self.frame]; 68 | _countLabel.backgroundColor = [UIColor clearColor]; 69 | _countLabel.textColor = [UIColor whiteColor]; 70 | _countLabel.textAlignment = NSTextAlignmentCenter; 71 | _countLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.75]; 72 | _countLabel.shadowOffset = CGSizeMake(0, -1); 73 | _countLabel.adjustsFontSizeToFitWidth = YES; 74 | _countLabel.numberOfLines = 1; 75 | _countLabel.font = [UIFont boldSystemFontOfSize:12]; 76 | _countLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; 77 | [self addSubview:_countLabel]; 78 | } 79 | 80 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 81 | { 82 | NSArray *subViews = self.subviews; 83 | if ([subViews count] > 1) 84 | { 85 | for (UIView *aSubView in subViews) 86 | { 87 | if ([aSubView pointInside:[self convertPoint:point toView:aSubView] withEvent:event]) 88 | { 89 | return YES; 90 | } 91 | } 92 | } 93 | if (point.x > 0 && point.x < self.frame.size.width && point.y > 0 && point.y < self.frame.size.height) 94 | { 95 | return YES; 96 | } 97 | return NO; 98 | } 99 | 100 | - (void)setCount:(NSUInteger)count 101 | { 102 | _count = count; 103 | 104 | /* 按count数目设置view的大小. */ 105 | CGRect newBounds = CGRectMake(0, 0, roundf(44 * ScaledValueForValue(count)), roundf(44 * ScaledValueForValue(count))); 106 | self.frame = CenterRect(newBounds, self.center); 107 | 108 | CGRect newLabelBounds = CGRectMake(0, 0, newBounds.size.width / 1.3, newBounds.size.height / 1.3); 109 | self.countLabel.frame = CenterRect(newLabelBounds, RectCenter(newBounds)); 110 | self.countLabel.text = [@(_count) stringValue]; 111 | 112 | [self setNeedsDisplay]; 113 | } 114 | 115 | #pragma mark - annimation 116 | 117 | - (void)willMoveToSuperview:(UIView *)newSuperview 118 | { 119 | [super willMoveToSuperview:newSuperview]; 120 | 121 | [self addBounceAnnimation]; 122 | } 123 | 124 | - (void)addBounceAnnimation 125 | { 126 | CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; 127 | 128 | bounceAnimation.values = @[@(0.05), @(1.1), @(0.9), @(1)]; 129 | bounceAnimation.duration = 0.6; 130 | 131 | NSMutableArray *timingFunctions = [[NSMutableArray alloc] initWithCapacity:bounceAnimation.values.count]; 132 | for (NSUInteger i = 0; i < bounceAnimation.values.count; i++) 133 | { 134 | [timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; 135 | } 136 | [bounceAnimation setTimingFunctions:timingFunctions.copy]; 137 | 138 | bounceAnimation.removedOnCompletion = NO; 139 | 140 | [self.layer addAnimation:bounceAnimation forKey:@"bounce"]; 141 | } 142 | 143 | #pragma mark draw rect 144 | 145 | - (void)drawRect:(CGRect)rect 146 | { 147 | CGContextRef context = UIGraphicsGetCurrentContext(); 148 | 149 | CGContextSetAllowsAntialiasing(context, true); 150 | 151 | UIColor *outerCircleStrokeColor = [UIColor colorWithWhite:0 alpha:0.25]; 152 | UIColor *innerCircleStrokeColor = [UIColor whiteColor]; 153 | UIColor *innerCircleFillColor = [UIColor colorWithRed:(255.0 / 255.0) green:(95 / 255.0) blue:(42 / 255.0) alpha:1.0]; 154 | 155 | CGRect circleFrame = CGRectInset(rect, 4, 4); 156 | 157 | [outerCircleStrokeColor setStroke]; 158 | CGContextSetLineWidth(context, 5.0); 159 | CGContextStrokeEllipseInRect(context, circleFrame); 160 | 161 | [innerCircleStrokeColor setStroke]; 162 | CGContextSetLineWidth(context, 4); 163 | CGContextStrokeEllipseInRect(context, circleFrame); 164 | 165 | [innerCircleFillColor setFill]; 166 | CGContextFillEllipseInRect(context, circleFrame); 167 | } 168 | 169 | @end 170 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/View/ClusterTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClusterTableViewCell.h 3 | // iOS_3D_ClusterAnnotation 4 | // 5 | // Created by PC on 15/7/7. 6 | // Copyright (c) 2015年 FENGSHENG. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ClusterTableViewCell : UITableViewCell 12 | 13 | @property (strong, nonatomic) UIButton *tapBtn; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/View/ClusterTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClusterTableViewCell.m 3 | // iOS_3D_ClusterAnnotation 4 | // 5 | // Created by PC on 15/7/7. 6 | // Copyright (c) 2015年 FENGSHENG. All rights reserved. 7 | // 8 | 9 | #import "ClusterTableViewCell.h" 10 | 11 | @implementation ClusterTableViewCell 12 | 13 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 14 | { 15 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 16 | 17 | if (self) 18 | { 19 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 20 | self.tapBtn = [[UIButton alloc] initWithFrame:self.bounds]; 21 | self.tapBtn.backgroundColor = [UIColor clearColor]; 22 | 23 | UIImage *tappedImage = [self createImageWithColor:[UIColor colorWithWhite:0.667 alpha:0.3] andSize:self.tapBtn.frame.size]; 24 | [self.tapBtn setBackgroundImage:tappedImage forState:UIControlStateHighlighted]; 25 | 26 | [self addSubview:self.tapBtn]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (UIImage *)createImageWithColor:(UIColor *)color andSize:(CGSize)size 33 | { 34 | CGRect rect=CGRectMake(0.0f, 0.0f, size.width, size.height); 35 | UIGraphicsBeginImageContext(size); 36 | CGContextRef context = UIGraphicsGetCurrentContext(); 37 | CGContextSetFillColorWithColor(context, [color CGColor]); 38 | CGContextFillRect(context, rect); 39 | 40 | UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); 41 | UIGraphicsEndImageContext(); 42 | return theImage; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/View/CustomCalloutView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomCalloutView.h 3 | // iOS_3D_ClusterAnnotation 4 | // 5 | // Created by PC on 15/7/9. 6 | // Copyright (c) 2015年 FENGSHENG. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @protocol CustomCalloutViewTapDelegate 13 | 14 | - (void)didDetailButtonTapped:(NSInteger)index; 15 | 16 | @end 17 | 18 | 19 | 20 | @interface CustomCalloutView : UIView 21 | 22 | @property (nonatomic, strong) NSArray *poiArray; 23 | 24 | @property (nonatomic, weak) id delegate; 25 | 26 | - (void)dismissCalloutView; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/ClusterAnnotation/View/CustomCalloutView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomCalloutView.m 3 | // iOS_3D_ClusterAnnotation 4 | // 5 | // Created by PC on 15/7/9. 6 | // Copyright (c) 2015年 FENGSHENG. All rights reserved. 7 | // 8 | 9 | #import "CustomCalloutView.h" 10 | #import "ClusterTableViewCell.h" 11 | 12 | 13 | const NSInteger kArrorHeight = 10; 14 | const NSInteger kCornerRadius = 6; 15 | 16 | const NSInteger kWidth = 260; 17 | const NSInteger kMaxHeight = 200; 18 | 19 | const NSInteger kTableViewMargin = 4; 20 | const NSInteger kCellHeight = 44; 21 | 22 | 23 | @interface CustomCalloutView() 24 | 25 | @property (nonatomic, strong) UITableView *tableview; 26 | 27 | @end 28 | 29 | @implementation CustomCalloutView 30 | 31 | - (void)setPoiArray:(NSArray *)poiArrayy 32 | { 33 | _poiArray = [NSArray arrayWithArray:poiArrayy]; 34 | CGFloat totalHeight = kCellHeight * self.poiArray.count + kArrorHeight + 2 *kTableViewMargin; 35 | CGFloat height = MIN(totalHeight, kMaxHeight); 36 | 37 | self.frame = CGRectMake(0, 0, kWidth, height); 38 | 39 | self.tableview.frame = CGRectMake(kCornerRadius, kTableViewMargin, kWidth - kCornerRadius * 2, height - kArrorHeight - kTableViewMargin * 2); 40 | 41 | [self setNeedsDisplay]; 42 | [self.tableview reloadData]; 43 | } 44 | 45 | - (void)dismissCalloutView 46 | { 47 | self.poiArray = nil; 48 | [self removeFromSuperview]; 49 | } 50 | 51 | #pragma mark - UITableViewDelegate 52 | 53 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 54 | { 55 | return kCellHeight; 56 | } 57 | 58 | #pragma mark - UITableViewDataSource 59 | 60 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 61 | { 62 | return self.poiArray.count; 63 | } 64 | 65 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 66 | { 67 | static NSString *identifier = @"ClusterCell"; 68 | ClusterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 69 | 70 | if (cell == nil) 71 | { 72 | cell = [[ClusterTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle 73 | reuseIdentifier:identifier]; 74 | } 75 | 76 | AMapPOI *poi = [self.poiArray objectAtIndex:indexPath.row]; 77 | cell.textLabel.text = poi.name; 78 | cell.detailTextLabel.text = poi.address; 79 | 80 | [cell.tapBtn addTarget:self action:@selector(detailBtnTap:) forControlEvents:UIControlEventTouchUpInside]; 81 | cell.tapBtn.tag = indexPath.row; 82 | 83 | return cell; 84 | } 85 | 86 | #pragma mark - TapGesture 87 | 88 | - (void)detailBtnTap:(UIButton *)button 89 | { 90 | if ([self.delegate respondsToSelector:@selector(didDetailButtonTapped:)]) 91 | { 92 | [self.delegate didDetailButtonTapped:button.tag]; 93 | } 94 | } 95 | 96 | #pragma mark - draw rect 97 | 98 | - (void)drawRect:(CGRect)rect 99 | { 100 | [self drawInContext:UIGraphicsGetCurrentContext()]; 101 | 102 | self.layer.shadowColor = [[UIColor blackColor] CGColor]; 103 | self.layer.shadowOpacity = 1.0; 104 | self.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); 105 | } 106 | 107 | - (void)drawInContext:(CGContextRef)context 108 | { 109 | CGContextSetLineWidth(context, 3.0); 110 | CGContextSetFillColorWithColor(context, [UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor); 111 | 112 | [self drawPath:context]; 113 | CGContextFillPath(context); 114 | } 115 | 116 | - (void)drawPath:(CGContextRef)context 117 | { 118 | CGRect rrect = self.bounds; 119 | CGFloat radius = kCornerRadius; 120 | CGFloat minx = CGRectGetMinX(rrect), 121 | midx = CGRectGetMidX(rrect), 122 | maxx = CGRectGetMaxX(rrect); 123 | CGFloat miny = CGRectGetMinY(rrect), 124 | maxy = CGRectGetMaxY(rrect)-kArrorHeight; 125 | 126 | CGContextMoveToPoint(context, midx+kArrorHeight, maxy); 127 | CGContextAddLineToPoint(context,midx, maxy+kArrorHeight); 128 | CGContextAddLineToPoint(context,midx-kArrorHeight, maxy); 129 | 130 | CGContextAddArcToPoint(context, minx, maxy, minx, miny, radius); 131 | CGContextAddArcToPoint(context, minx, minx, maxx, miny, radius); 132 | CGContextAddArcToPoint(context, maxx, miny, maxx, maxy, radius); 133 | CGContextAddArcToPoint(context, maxx, maxy, midx+kArrorHeight, maxy, radius); 134 | CGContextClosePath(context); 135 | } 136 | 137 | #pragma mark - Initialization 138 | 139 | - (id)initWithFrame:(CGRect)frame 140 | { 141 | self = [super initWithFrame:frame]; 142 | if (self) 143 | { 144 | self.backgroundColor = [UIColor clearColor]; 145 | 146 | self.tableview = [[UITableView alloc] init]; 147 | self.tableview.delegate = self; 148 | self.tableview.dataSource = self; 149 | 150 | [self addSubview:self.tableview]; 151 | } 152 | return self; 153 | } 154 | 155 | 156 | 157 | @end 158 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Configuration/APIKey.h: -------------------------------------------------------------------------------- 1 | // 2 | // APIKey.h 3 | // SearchV3Demo 4 | // 5 | // Created by songjian on 13-8-14. 6 | // Copyright (c) 2013年 songjian. All rights reserved. 7 | // 8 | 9 | #ifndef SearchV3Demo_APIKey_h 10 | #define SearchV3Demo_APIKey_h 11 | 12 | /* 使用高德SearchV3, 请首先注册APIKey, 注册APIKey请参考 http://api.amap.com 13 | */ 14 | const static NSString *APIKey = @"da09a34dcc33ae17471ae9fdb45d26d7"; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIRequiredDeviceCapabilities 31 | 32 | armv7 33 | 34 | UISupportedInterfaceOrientations 35 | 36 | UIInterfaceOrientationPortrait 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3D/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // iOS_ClusterAnnotation_3D 4 | // 5 | // Created by liubo on 2016/12/16. 6 | // Copyright © 2016年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3DUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /iOS_ClusterAnnotation_3DUITests/iOS_ClusterAnnotation_3DUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // iOS_ClusterAnnotation_3DUITests.m 3 | // iOS_ClusterAnnotation_3DUITests 4 | // 5 | // Created by hanxiaoming on 16/12/20. 6 | // Copyright © 2016年 AutoNavi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iOS_ClusterAnnotation_3DUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation iOS_ClusterAnnotation_3DUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | XCUIApplication *app = [[XCUIApplication alloc] init]; 39 | XCUIElement *element = [[[[[[[app.otherElements containingType:XCUIElementTypeNavigationBar identifier:@"Cluster Annotations"] childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther] elementBoundByIndex:1]; 40 | 41 | [element doubleTap]; 42 | [element swipeRight]; 43 | [element swipeLeft]; 44 | [element twoFingerTap]; 45 | 46 | // 重新加载 47 | XCUIElement *button = app.buttons[@"\u91cd\u65b0\u52a0\u8f7d\u6570\u636e"]; 48 | [button tap]; 49 | 50 | [element doubleTap]; 51 | [element twoFingerTap]; 52 | 53 | [[[element childrenMatchingType:XCUIElementTypeOther] elementBoundByIndex:5] tap]; 54 | 55 | XCUIElement *appleStaticText = [app.tables.cells elementBoundByIndex:0]; 56 | [appleStaticText tap]; 57 | 58 | XCUIElement *clusterAnnotationsButton = app.navigationBars[@"POI\u4fe1\u606f (AMapPOI)"].buttons[@"Cluster Annotations"]; 59 | [clusterAnnotationsButton tap]; 60 | 61 | } 62 | 63 | @end 64 | --------------------------------------------------------------------------------