iOS 【地圖繪製行政區域邊界及填充】
阿新 • • 發佈:2019-01-31
很久沒有寫東西了,因為最近的專案要趕在國慶中秋前夕上架,忙碌了2個多月的時間。對地圖繪製這塊整理了一下,希望能讓大家少走彎路。
想法
之前看到在網頁端有地理區域的繪製和填充,覺得挺不錯。在網上扒了扒,沒找到合適的方案。實現效果如下:
環境
- iOS 開發環境
- 高德地圖 SDK
- swift 4.1 語言環境
準備
- 山東省邊界點資料集合
- 合理使用高德 API
實現
(1)查詢出山東省行政區域邊界點集合
/// 區域規劃邊界點集合拼接字串 回撥閉包 typealias SearchPolylinesBlock = ([String]) -> Void /// AMap 檢索物件 lazy var mapSearch = { return AMapSearchAPI() }()
/// 根據關鍵字查詢行政區域邊界 /// /// - Parameters: /// - keywords: 關鍵字 /// - polylinesCallBack: <#polylinesCallBack description#> func searchPostionLine(keywords: String, polylinesCallBack: @escaping SearchPolylinesBlock) { self.searchPolylinesBlock = polylinesCallBack let request = AMapDistrictSearchRequest() request.keywords = keywords request.requireExtension = true self.mapSearch?.aMapDistrictSearch(request) }
/// 行政區域查詢回撥函式 /// /// - Parameters: /// - request: <#request description#> /// - response: <#response description#> func onDistrictSearchDone(_ request: AMapDistrictSearchRequest!, response: AMapDistrictSearchResponse!) { if response.count == 0 { print("規劃失敗,區域規劃結果不存在!") return } if response.districts.count == 0 { print("規劃失敗,區域規劃結果不存在!") return } /// 行政區劃 邊界點 var pointLinesArr = [String]() for (_, district) in response.districts.enumerated() { if district.polylines.count == 0 { continue } for (_, polylineStr) in district.polylines.enumerated() { pointLinesArr.append(polylineStr) } } if let block = self.searchPolylinesBlock { block(pointLinesArr) } }
(2)處理邊界點集合資料
先根據具體情況去選擇解析字串的的格式,目前 amap api 返回的則是內外分隔符不同的情況。具體情況具體分析。
/// 解析經緯度字串(適用於 內外分隔符 不同的情況)
///
/// - Parameters:
/// - pathStr: 經緯度字串(示例:114.036217,22.524128;114.036079,22.52401;114.036011,22.523979)
/// - separatorIn: 一組經緯度 經度和緯度 之間的分隔符
/// - separatorOut: 每 兩組經緯度 之間的間隔符
/// - Returns: [CLLocationCoordinate2D]
func coordinatesForString(_ pathStr: String?, separatorIn: Character = ",", separatorOut: Character = ";") -> [CLLocationCoordinate2D] {
guard let pathStr = pathStr else { return [] }
let coorStrs = pathStr.split(separator: separatorOut)
var results = [CLLocationCoordinate2D]()
for coorStr in coorStrs {
let coordinate = coorStr.split(separator: separatorIn)
guard coordinate.count == 2, let lng = Double(coordinate[0]), let lat = Double(coordinate[1]) else { continue }
let point = CLLocationCoordinate2D(latitude: lat, longitude: lng)
results.append(point)
}
return results
}
/// 解析經緯度字串(適用於 內外分隔符 相同的情況)
/// warning:
///
/// - Parameters:
/// - pathStr: 經緯度字串(示例:114.036217,22.524128,114.036079,22.52401,114.036011,22.523979)
/// - separator: 每 兩組經緯度 之間的間隔符 & 一組經緯度 經度和緯度 之間的分隔符
/// - Returns: [CLLocationCoordinate2D]
func coordinatesForString(_ pathStr: String?, separator: Character = ",") -> [CLLocationCoordinate2D] {
guard let pathStr = pathStr else { return [] }
let coorStrs = pathStr.split(separator: separator)
var results = [CLLocationCoordinate2D]()
for index in stride(from: 0, to: coorStrs.count, by: 2) {
guard (index + 1 >= coorStrs.count), let lng = Double(coorStrs[index]), let lat = Double(coorStrs[index + 1]) else { continue }
let point = CLLocationCoordinate2D(latitude: lat, longitude: lng)
results.append(point)
}
return results
}
(3)描邊填充
// 山東省 區域邊界
AMapUtils.share.searchPostionLine(keywords: "山東省") { [weak self] (pointsStrArr) in
guard self != nil else { return }
// 將規範化的字串 —> [CLLocationCoordinate2D]
var lineArr = [SearchPolyline]()
for (_, pointsStr) in pointsStrArr.enumerated() {
var coors: [CLLocationCoordinate2D] = BLLModuleFactory().returnSearchBll().coordinatesForString(pointsStr, separatorIn: ",", separatorOut: ";")
// 填充內部區域(一部分一部分的填充)
let gonlay = MAPolygon.init(coordinates: &coors, count: UInt(coors.count))
self?.myMap.add(gonlay)
let polyline = SearchPolyline(coordinates: &coors, count: UInt(coors.count))
guard let line = polyline else { return } // 沒有規劃出線路來
line.polylineType = PolylineType.ShandongProvince
lineArr.append(line)
}
self?.myMap.addOverlays(lineArr)
}
幾點注意
(1)AMapUtils 為自定義工具類,方便呼叫,讀者可自行定義;
(2)SearchPolyline 為自定義描線,繼承於 MAPolyline,為了處理業務的複雜邏輯,讀者可自行定義;
(3)描邊和填充內部區域用的是 amap 的不同填充物件(MAPolygon、MAPolyline);
(4)區域規劃一般來說不是封閉的線,是由很多段線條組成的,所以新增線時要一段一段的新增,不然就會頭尾相連亂掉。同理,填充內部區域時也需分段,不然會出現重疊的區域。