MapKit上にポリラインの経路を描画するには
経路を表すCSVファイルの内容は以下のようにする(カンマの後ろに半角スペースは入れない)。
35.7319802777778,139.7251925
35.7319802777778,139.7251925
35.7319238888889,139.725016666667
35.7319033333333,139.724955833333
35.7315475,139.725145833333
35.7314455555556,139.724840833333
35.7313033333333,139.724543611111
35.73079,139.724795277778
35.7307391666667,139.724551111111
35.7305155555556,139.724314444444
35.7303875,139.724231111111
35.7302358333333,139.72404
35.7298288888889,139.723658333333
35.7293147222222,139.723254722222
35.7291594444444,139.723546666667
CSVファイルをパースするには以下のようなメソッドを用意する。
MapLineViewController.m
...
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
...
points = [self getLocationPointsFromCsvFile:@"route"];
_routeView = [[CSMapRouteLayerView alloc] initWithRoute:points mapView:_mapView];
...
}
}
...
- (NSMutableArray *)getLocationPointsFromCsvFile:(NSString *)filename {
//
// 内部のリソースの地点の集合をロードする
//
NSString* filePath = [[NSBundle mainBundle] pathForResource:filename ofType:@"csv"];
NSString* fileContents = [NSString stringWithContentsOfFile:filePath];
NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableArray* points = [[NSMutableArray alloc] initWithCapacity:pointStrings.count];
for(int idx = 0; idx < pointStrings.count; idx++)
{
// 文字列を分解して緯度と軽度を取得する
NSString* currentPointString = [pointStrings objectAtIndex:idx];
NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];
CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue];
CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];
CLLocation* currentLocation = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
[points addObject:currentLocation];
}
return points;
}
実際にMapKit上に経路を描画するには以下のようにする。
CSMapRouteLayerView.h
#import <MapKit/MapKit.h>
@interface CSMapRouteLayerView : UIView <MKMapViewDelegate>
{
MKMapView* _mapView;
NSArray* _points;
UIColor* _lineColor;
}
-(id) initWithRoute:(NSArray*)routePoints mapView:(MKMapView*)mapView;
@property (nonatomic) NSArray* points;
@property (nonatomic) MKMapView* mapView;
@property (nonatomic) UIColor* lineColor;
@end
CSMapRouteLayerView.m
#import "CSMapRouteLayerView.h"
@implementation CSMapRouteLayerView
@synthesize mapView = _mapView;
@synthesize points = _points;
@synthesize lineColor = _lineColor;
-(id) initWithRoute:(NSArray*)routePoints mapView:(MKMapView*)mapView
{
self = [super initWithFrame:CGRectMake(0, 0, mapView.frame.size.width, mapView.frame.size.height)];
[self setBackgroundColor:[UIColor clearColor]];
[self setMapView:mapView];
[self setPoints:routePoints];
// 表示領域の上限、下限などを決める
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx < self.points.count; idx++)
{
CLLocation* currentLocation = [self.points objectAtIndex:idx];
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
}
MKCoordinateRegion region;
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
[self.mapView setRegion:region];
[self.mapView setDelegate:self];
[self.mapView addSubview:self];
return self;
}
- (void)drawRect:(CGRect)rect
{
// 画面遷移中や描画中の点がない場合のみ描画する
if(!self.hidden && nil != self.points && self.points.count > 0)
{
CGContextRef context = UIGraphicsGetCurrentContext();
if(nil == self.lineColor)
self.lineColor = [UIColor blueColor];
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
// 太さ2.0でラインを引く
CGContextSetLineWidth(context, 2.0);
for(int idx = 0; idx < self.points.count; idx++)
{
CLLocation* location = [self.points objectAtIndex:idx];
CGPoint point = [_mapView convertCoordinate:location.coordinate toPointToView:self];
if(idx == 0)
{
// 最初の点に移動
CGContextMoveToPoint(context, point.x, point.y);
}
else
{
// ラインを引く
CGContextAddLineToPoint(context, point.x, point.y);
}
}
CGContextStrokePath(context);
}
}
#pragma mark mapView delegate functions
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
// 表示領域を変更しているあいだはビューの描画を止める。
// 画面移動中に間違った位置にラインが引かれるのを防ぐ。
self.hidden = YES;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// 経路表示を再度可能にし、場所をセットし直す
self.hidden = NO;
[self setNeedsDisplay];
}
@end