在iPhone上使用MapKit查找两点之间的路径/路线

9

我正在尝试在MapKit上找到两个地点之间的路径。我只有两个地点的信息,现在需要找到这些点之间的准确路径,并使用MapKit绘制一条直线。我查阅了几个示例,它们都使用了.csv文件。在那个.csv文件中,他们存储了完整路径的纬度和经度值,并基于这些值画出线路。

但是在这里,我想在不知道路径的情况下绘制一条线路。所以有没有办法动态地找到路径并画出一条线路?

5个回答

13
以下是查找路径并在两个位置之间绘制线条的代码。
要实现以下类:
_mapRecord = [[PSMapDirection alloc] initWithFrame:CGRectMake(0.0, 49.0, 320.0, 411.0)];
[self.view addSubview:_mapRecord];

MapDirection.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "RegexKitLite.h"

@interface MapDirection : UIView<MKMapViewDelegate> 
{    
    MKMapView* mapView;
    NSArray* routes;    
    BOOL isUpdatingRoutes;
}

-(void) showRouteFrom: (MKAnnotation*) f to:(MKAnnotation*) t;

@end

MapDirection.m

#import "MapDirection.h"

@interface MapDirection()
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) from to: (CLLocationCoordinate2D) to;
-(void) centerMap;

@end

- (id) initWithFrame:(CGRect) frame
{
    self = [super initWithFrame:frame];
    if (self != nil) 
    {
        mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
        mapView.showsUserLocation = NO;
        [mapView setDelegate:self];
        [self addSubview:mapView];      
    }
    return self;
}

- (NSMutableArray *)decodePolyLine: (NSMutableString *)encoded 
{
    [encoded replaceOccurrencesOfString:@"\\\\" withString:@"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])];
    NSInteger len = [encoded length];
    NSInteger index = 0;
    NSMutableArray *array = [[NSMutableArray alloc] init];
    NSInteger lat=0;
    NSInteger lng=0;
    while (index < len) 
    {
        NSInteger b;
        NSInteger shift = 0;
        NSInteger result = 0;
        do 
        {
            b = [encoded characterAtIndex:index++] - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lat += dlat;
        shift = 0;
        result = 0;
        do
        {
            b = [encoded characterAtIndex:index++] - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lng += dlng;
        NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
        NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
        //printf("[%f,", [latitude doubleValue]);
        //printf("%f]", [longitude doubleValue]);
        CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
        [array addObject:loc];
    }   
    return array;
}

-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t 
{
    NSString* saddr = [NSString stringWithFormat:@"%f,%f", f.latitude, f.longitude];
    NSString* daddr = [NSString stringWithFormat:@"%f,%f", t.latitude, t.longitude];

    NSString* apiUrlStr = [NSString stringWithFormat:@"http://maps.google.com/maps?output=dragdir&saddr=%@&daddr=%@", saddr, daddr];
    NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
    //NSLog(@"api url: %@", apiUrl);
    NSError* error = nil;
    NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
    NSString *encodedPoints = [apiResponse stringByMatching:@"points:\\\"([^\\\"]*)\\\"" capture:1L];   
    return [self decodePolyLine:[encodedPoints mutableCopy]];
}

-(void) centerMap
{
    MKCoordinateRegion region;
    CLLocationDegrees maxLat = -90.0;
    CLLocationDegrees maxLon = -180.0;
    CLLocationDegrees minLat = 90.0;
    CLLocationDegrees minLon = 180.0;
    for(int idx = 0; idx < routes.count; idx++)
    {
        CLLocation* currentLocation = [routes 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;
    }
    region.center.latitude     = (maxLat + minLat) / 2.0;
    region.center.longitude    = (maxLon + minLon) / 2.0;
    region.span.latitudeDelta = 0.01;
    region.span.longitudeDelta = 0.01;

    region.span.latitudeDelta  = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
    region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);
    [mapView setRegion:region animated:YES];
}

-(void) showRouteFrom: (MKAnnotation*) f to:(MKAnnotation*) t 
{   
    if(routes) 
    {
    [mapView removeAnnotations:[mapView annotations]];
    }

    [mapView addAnnotation:f];
    [mapView addAnnotation:t];

    routes = [self calculateRoutesFrom:f.coordinate to:t.coordinate];
    NSInteger numberOfSteps = routes.count;

    CLLocationCoordinate2D coordinates[numberOfSteps];
    for (NSInteger index = 0; index < numberOfSteps; index++) 
    {
        CLLocation *location = [routes objectAtIndex:index];
        CLLocationCoordinate2D coordinate = location.coordinate;
        coordinates[index] = coordinate;
    }
    MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
    [mapView addOverlay:polyLine];
    [self centerMap];
}

#pragma mark MKPolyline delegate functions
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay 
{
    MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
    polylineView.strokeColor = [UIColor purpleColor];
    polylineView.lineWidth = 5.0;
    return polylineView;
}

@end

起点为"41.967659,-87.627869",终点为"41.574361,-91.083069"的导航路线示例:

地图路线


2
这个谷歌API不能用于提供逐步导航。它也不能用于在任何不是谷歌的地图上打印路线,因此对于iOS6版本将不再有效。不管怎样,这是最好的方法。我正在使用非常类似的东西来达到同样的目的。 - The dude
不要听 @Thedude 的话,这段代码在 iOS6 和 iOS7 上完美运行,我亲自测试过了。作者加一分👍。 - abbood
@abbood 因为我正在使用私有系统,所以不允许分享。 - The dude
@abbood - 感谢您的更新。如果我没有忘记,最初的iOS 6是在2012年9月19日发布的,而问题和解决方案则是在一个月之前讨论的! - alloc_iNit
1
有没有办法找到源点到目的地之间的时间持续情况? - Ali Raza
显示剩余24条评论

7
我能够帮助您绘制两个点(位置)之间的路径。
首先,请从此链接下载GoogleMap sdk并将其集成到您的应用程序中。
现在需要API密钥,您可以按此链接中给出的指南创建该密钥。
下面是绘制两个位置之间的谷歌地图方向的代码。
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t {
NSString* saddr = [NSString stringWithFormat:@"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:@"%f,%f", t.latitude, t.longitude];


NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&sensor=false&avoid=highways&mode=driving",saddr,daddr]];

NSError *error=nil;

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;

[request setURL:url];
[request setHTTPMethod:@"POST"];

NSURLResponse *response = nil;

NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: &error];

NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONWritingPrettyPrinted error:nil];

return [self decodePolyLine:[self parseResponse:dic]];
}
- (NSString *)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:@"routes"];
NSDictionary *route = [routes lastObject];
if (route) {
    NSString *overviewPolyline = [[route objectForKey:
                                   @"overview_polyline"] objectForKey:@"points"];
    return overviewPolyline;
}
return @"";
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc]
                            initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:@"\\\\" withString:@"\\"
                            options:NSLiteralSearch
                              range:NSMakeRange(0,
                                                [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
    NSInteger b;
    NSInteger shift = 0;
    NSInteger result = 0;
    do {
        b = [encoded characterAtIndex:index++] - 63;
        result |= (b & 0x1f) << shift;
        shift += 5;
    } while (b >= 0x20);
    NSInteger dlat = ((result & 1) ? ~(result >> 1)
                      : (result >> 1));
    lat += dlat;
    shift = 0;
    result = 0;
    do {
        b = [encoded characterAtIndex:index++] - 63;
        result |= (b & 0x1f) << shift;
        shift += 5;
    } while (b >= 0x20);
    NSInteger dlng = ((result & 1) ? ~(result >> 1)
                      : (result >> 1));
    lng += dlng;
    NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
    NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
    CLLocation *location = [[CLLocation alloc] initWithLatitude:
                            [latitude floatValue] longitude:[longitude floatValue]];
    [array addObject:location];
}
return array;
}
- (void)loadMapViewWithDirection {

float lat = 23.050671;
float lng = 72.541351;

GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:lat
                                                        longitude:lng
                                                             zoom:10];

GMSMapView  * mapView = [GMSMapView mapWithFrame:CGRectMake(0, 75, 320, self.view.frame.size.height-kHeaderRect.size.height) camera:camera];
self.mapView.myLocationEnabled = YES;


float sourceLatitude = 23.050671;
float sourceLongitude = 72.541351;

float destLatitude = 23.036138;
float destLongitude = 72.603836;

GMSMarker *sourceMarker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(sourceLatitude, sourceLongitude);
marker.map = self.mapView;

GMSMarker *destMarker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(destLatitude, destLongitude);
marker.map = self.mapView;

self.mapView.delegate = self;

   [self drawDirection:CLLocationCoordinate2DMake(sourceLatitude, sourceLongitude) and:CLLocationCoordinate2DMake(destLatitude, destLongitude)];


[self.view addSubview:self.mapView];
}
- (void) drawDirection:(CLLocationCoordinate2D)source and:(CLLocationCoordinate2D) dest {


GMSPolyline *polyline = [[GMSPolyline alloc] init];
GMSMutablePath *path = [GMSMutablePath path];

NSArray * points = [self calculateRoutesFrom:source to:dest];

NSInteger numberOfSteps = points.count;

for (NSInteger index = 0; index < numberOfSteps; index++)
{
    CLLocation *location = [points objectAtIndex:index];
    CLLocationCoordinate2D coordinate = location.coordinate;
    [path addCoordinate:coordinate];
}

polyline.path = path;
polyline.strokeColor = [UIColor redColor];
polyline.strokeWidth = 2.f;
polyline.map = self.mapView;

// Copy the previous polyline, change its color, and mark it as geodesic.
polyline = [polyline copy];
polyline.strokeColor = [UIColor greenColor];
polyline.geodesic = YES;
polyline.map = self.mapView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadMapViewWithDirection];   
}

集成什么?SDKDemo源文件还是捆绑包? - chandru
你需要添加GoogleMaps.framework和SDKDemos是演示应用程序供参考。 - Dhaval

2

1
是的,我已经看到了它们两个。他们都在使用Google API。但是我正在尝试在不使用Google API的情况下完成这项任务。有可能吗? - Sasi
我在哪里可以获得Google API文件? - Sasi

1

我认为你无法在本地完成这个任务。实现一个用于查找两个GPS点之间路径的算法需要大量的输入数据(来自地图的数据),而你没有这些数据。只有地图提供商才能负担得起实现这样的算法并公开API供使用。我认为Google有路由API,但我还没有尝试过...


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接