【Swift】MKOverlayの使い方。地図に円や多角形を描く。(Swift 2.1、XCode 7.2)
2020年6月16日
円や多角形も地図に描画できる
過去の記事でMKMapView(以下、マップビュー)のピンとピンの間に直線を引く方法を説明したことがある。⇒「記事」
マップビューには直線以外の円や多角形も描くことができる。例えば、ある地点からの半径10m以内の領域を表示したり、区画を四角で囲んだりなど、地図上の対象領域を表示するのに役に立ちそうだ。
そこで本記事ではピンの座標にもとづいて地図の上に図形を描く方法を説明する。
実装イメージ
地図に刺したピンをタップすると、ピンを頂点とした多角形が描画される動きを実装する。ただし、ピンが1個の状態でタップしたときはピンを中心とした半径100mの円が描画され、ピンが2個の状態でタップするとピンとピンの間の直線を直径とした円を描画するようにする。
以降の手順は「Map Kit Viewの使い方」の続きから行うので、実装を試してみる人は先に読んでおくことをお勧めする。
実装する
デバイス画面にLong Press Gesture Recognizerを配置する(下図赤矢印)。紫枠のアシスタントエディタボタンを押してViewController.swiftを開く。Ctrlキーを押しながら黄緑枠のジェスチャーリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる。
Connectionに「Action」、Nameに「pressMap」、Typeに「UILongPressGestureRecognizer」を設定しConnectボタンを押す。これで地図を長押ししたときのイベントをソースコードで受けれるようになった。
ViewController.swiftを以下のコードに変更する。
地図にピンを刺すときに、クラス変数の「ピンのリスト」に刺したピンを追加している。ピンがタップされたら「ピンのリスト」に格納されているピンの個数を確認し、個数に応じて多角形または円を地図に描画し、「ピンのリスト」を空にする。
「ピンのリスト」を空にすることで、図形を描画したあとに続けて別の図形を描画できるようになる。
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
// // ViewController.swift // import UIKit import MapKit class ViewController: UIViewController,MKMapViewDelegate{ @IBOutlet weak var testMapView: MKMapView! //ピンのリスト var coordinateList = [CLLocationCoordinate2D]() //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //デリゲート先を自分に設定する。 testMapView.delegate = self //中心座標 let center = CLLocationCoordinate2DMake(35.690553, 139.699579) //表示範囲 let span = MKCoordinateSpanMake(0.005, 0.005) //中心座標と表示範囲をマップに登録する。 let region = MKCoordinateRegionMake(center, span) testMapView.setRegion(region, animated:true) } //マップビュー長押し時の呼び出しメソッド @IBAction func pressMap(sender: UILongPressGestureRecognizer) { //マップビュー内のタップした位置を取得する。 let location:CGPoint = sender.locationInView(testMapView) if (sender.state == UIGestureRecognizerState.Ended){ //タップした位置を緯度、経度の座標に変換する。 let mapPoint:CLLocationCoordinate2D = testMapView.convertPoint(location, toCoordinateFromView: testMapView) //ピンを作成してマップビューに追加する。 let annotation = MKPointAnnotation() annotation.coordinate = CLLocationCoordinate2DMake(mapPoint.latitude, mapPoint.longitude) testMapView.addAnnotation(annotation) //追加したピンをリストに追加する。 coordinateList.append(CLLocationCoordinate2D(latitude: mapPoint.latitude, longitude: mapPoint.longitude)) } } //ピンタップ時の呼び出しメソッド func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) { //ピンの数で場合分け if(coordinateList.count == 1) { //ピンを中心に半径100mの円をマップビューに追加する。 let overlay = MKCircle(centerCoordinate: CLLocationCoordinate2D(latitude:coordinateList[0].latitude, longitude: coordinateList[0].longitude), radius:100) testMapView.addOverlay(overlay) } else if(coordinateList.count == 2) { //2点間の中心座標を求める。 let centerX = (coordinateList[0].longitude + coordinateList[1].longitude)/2 let centerY = (coordinateList[0].latitude + coordinateList[1].latitude)/2 //2点間の距離から円の半径を求める。 let aaa:CLLocation = CLLocation(latitude: coordinateList[0].latitude, longitude: coordinateList[0].longitude) let bbb:CLLocation = CLLocation(latitude: coordinateList[1].latitude, longitude: coordinateList[1].longitude) let radius = aaa.distanceFromLocation(bbb)/2 //2点間の直線を直径とした縁をマップビューに追加する。 let overlay = MKCircle(centerCoordinate: CLLocationCoordinate2D(latitude: centerY, longitude: centerX), radius:radius) testMapView.addOverlay(overlay) } else { //ピンを頂点にした多角形をマップビューに追加する。 let overlay = MKPolygon(coordinates: &coordinateList, count: coordinateList.count) testMapView.addOverlay(overlay) } } //描画前の呼び出しメソッド func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer { //円と多角形の場合でインスタンスのクラスを分ける。 let renderer:MKOverlayPathRenderer if overlay is MKCircle { renderer = MKCircleRenderer(overlay:overlay) } else { renderer = MKPolygonRenderer(overlay:overlay) } //図形の色をランダム生成する。 renderer.fillColor = UIColor(red: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 0.5) //ピンのリストをすべて削除する。 coordinateList.removeAll() return renderer; } } |
以下は実際のプレイ動画