LoginSignup
9
8

More than 5 years have passed since last update.

MapKit上にポリラインの経路を描画するには

Posted at

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
9
8
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
9
8