LoginSignup
77
72

More than 5 years have passed since last update.

MKMapView のメモ

Last updated at Posted at 2012-12-26

3種類の座標系

  • 緯度経度
    • CLLocationCoordinate2D
    • 緯度経度で表される座標系、原点はアフリカ大陸西方沖
  • マップ座標系
    • MK〜
    • メルカトル地図の座標系、原点は左上
  • Core Graphics 座標系
    • CG〜
    • UIView における座標系、原点は左上

緯度経度

  • CLLocationCoordinate2D
  • 緯度経度値をもつ構造体. WGS84(米国で採用されている世界測地系)で定義される座標系
  • latitude: 緯度. CLLocationDegrees (double) 型
  • longitude: 経度. CLLocationDegrees (double) 型
  • 『無効な値』を表す場合、lat/lon それぞれが NaN となる模様. isnan() 関数で判定できる
  • 緯度経度なので、本初子午線と赤道を境にマイナス値を取る場合もあり得る
  • 日本はだいたい、{35, 135} 前後くらいになる
  • {0, 0} はアフリカ大陸西方沖、赤道と子午線が交差する点
    • 拡大すると妙な島がぽつんと浮かんでいる。おそらく聖地(Google Maps では存在しない?) CF5h3JNUgAAXXDL.png CF5h3GrUIAA-Szz.png

マップ座標系

他と区別するためにマップ座標系と勝手に呼称する。

  • MKMapRect
  • MKMapPoint
  • MKMapSize

MapView のあの見た目はメルカトル図法になる。原点は左上、北米大陸の左上の日付変更線上が {0, 0} になる。この場合の地図は西洋を中心に描かれた世界地図である。

MKMapPoint は普通マイナス値にはならないが、何かしらのエラーの際には {-1, -1} となり得る(後述)

とりあえず Apple の資料と MKGeometry.h は眺めるべし

座標系変換・衝突判定

MKMapRect を NSString に変換

文字列としてログ出力
NSLog(MKStringFromMapRect(mapRect));

MKMapView の表示範囲を MKMapRect で取得

地図の表示範囲を取得
MKMapRect visibleRect = mapView.visibleMapRect;

MKMapPoint から CLLocationCoordinate2D に変換

メルカトル図法の点から緯度経度に変換
MKMapPoint p = MKMapPointMake(100.0, 200.0);
CLLocationCoordinate2D coordinate = MKCoordinateForMapPoint;

CLLocationCoordinate2D から MKMapPoint に変換

緯度経度からメルカトル図法の点に変換
CLLocationCoordinate2D coordinate = CLLocationCoordinate2D(35.0, 135.0);
MKMapPoint p = MKMapPointForCoordinate(coordinate);

注意

例えば以下のようにあり得ない緯度経度を指定すると、MKMapPoint には {-1, -1} が返ってくる。この座標は画面上には存在しない。

こんな場所はありません
CLLocationCoordinate2D coordinate = CLLocationCoordinate2D(999999, 999999);
MKMapPoint p = MKMapPointForCoordinate(coordinate);

MKMapPoint と MKMapRect の衝突判定

マップ座標がマップ矩形の内側にあるかを判定する方法。

点が画面内にあるか
MKMapRect mapRect = mapView.visibleMapRect; // 表示している画面矩形
MKMapPoint point = MKMapPointMake(100, 200.0); // メルカトル図法上での点

// 点が画面内にあれば YES が返る
BOOL isInMapRect = MKMapRectContainsPoint(mapRect, point);

CLLocationCoordinate2D と MKCircle の衝突判定

緯度経度と MKCircle との衝突判定を行う方法。ユーザーの座標が半径〜mの円の内側にあるかを判定する。

ユーザーがヨドバシカメラ梅田の近所にいるかを判定
CLLocationCoordinate2D yodobashiUmedaPoint = CLLocationCoordinate2DMake(34.704172, 135.496324); // 中心緯度経度
CLLocationDistance yodobashiUmedaRadius = 100.0; // 半径100m
MKCircle *yodobashiUmedaArea = [MKCircle circleWithCenterCoordinate:yodobashiUmedaPoint radius: yodobashiUmedaRadius];

// ユーザーの座標
CLLocationCoordinate2D userCoordinate = mapView.userLocation.coordinate;
MKMapPoint userLocationMapPoint = MKMapPointForCoordinate(userCoordinate);

// パスをオフスクリーン描画
MKCircleRenderer *yodobashiUmedaRenderer = [[MKCircleRenderer alloc] initWithCircle: yodobashiUmedaArea];
[yodobashiUmedaRenderer createPath];
// ユーザーの座標を CGPoint に変換
CGPoint userLocationPoint = [yodobashiUmedaRenderer pointForMapPoint:userLocationMapPoint];

// ユーザーの座標がパスに含まれるかを判定
if (CGPathContainsPoint(yodobashiUmedaRenderer.path, NULL, userLocationPoint, NO)) {
    // 近くにいるよ
}
else {
    // いないよ
}

2点間の距離をメートル単位で計算

MKMapPoint point1 = MKMapPointForCoordinate(coordinate1);
MKMapPoint point2 = MKMapPointForCoordinate(coordinate2);
CLLocationDistance distance = MKMetersBetweenMapPoints(point1, point2);

CLLocationDistance はメートル単位。

77
72
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
77
72