2010-05-14 48 views
53

我想绘制地图上两个位置之间的路线。像导游一样。当游客点击另一个地点时,我希望能够绘制路线;并告知距离当前位置的距离。在iPhone SDK中的MapKit中绘制路线

我知道互联网上的网站,它告诉如何在地图上绘制多段线。但是,大多数示例都有一个带有各种坐标的预加载的.csv文件。

是否有另一种方式从Google或任何其他提供商处获取坐标,因为该位置是动态选择的。

如果否,我如何获得中间坐标信息?

iOS 6是否提供了解决此问题的任何直接方法?

+0

试试这个,唯一希望这将有助于ühttps://github.com/Surya121/SBMapWithRoute – iCoder4777 2011-12-26 07:26:38

+0

HTTP://iphonegeeksworld.wordpress。COM/2010/09/08 /绘图路线 - 到 - 使用 - 非官方谷歌,地图,方向-API的MKMapView-/ – viral 2012-08-12 08:52:22

+0

如果您正在使用的代码此更新neccessary 的http://计算器.COM /问题/ 8166179 /正则表达式和-的iOS5-stringbymatching-nsregularexpression – 2013-06-26 08:49:57

回答

24

这是一个棘手的问题。 MapKit没有办法做到这一点:在知道坐标时很容易绘制线条,但MapKit不会让您访问道路或其他路线信息。我想说你需要调用一个外部API来获取你的数据。

我一直在玩cloudmade.com API。矢量流服务器应该返回你需要的东西,然后你可以在你的地图上绘制它。但是,Google地图与Cloudmade使用的地图之间的差异可能会让您想要一路使用cloudmade地图:它们与MapKit具有相同的效果。

P.S .:其他地图提供商 - Google,Bing等也可能提供等效的数据提要。我刚刚在OSM/Cloudmade上看过。

P.P.S .:这些都不是新鲜的东西!祝你好运!

12

Andiih说得对。 MapKit不会让你这样做。不幸的是,Google不会让你做你想做的事情。

当苹果宣布MapKit和所有的,他们还明确指出,任何导航应用将是BYOM:带上你自己的地图,所以任何导航的应用程序使用他们自己的一套制图工具。

谷歌的服务条款的限制,你甚至从他们的地图,上面显示的路线:

http://code.google.com/intl/de/apis/maps/iphone/terms.html

许可限制:

10。9使用服务或内容的任何产品,系统,或应用 用于或与连接:

的(a)实时导航或路径 指导,包括但不限于: 反过来由转动路线引导即 同步到 用户的启用传感器的设备的位置; (b) 自动或自主控制车辆行为的任何系统或功能;或

(c)调度,车队管理, 公司资产跟踪或类似 企业应用程序(谷歌 地图API可以 (如汽车,公交车或其他 车辆)只要用于跟踪资产跟踪 应用程序提供给公众 不收费。例如, 你也可以提供一个免费的公共地图API 实现,显示实时 公共交通或其他交通 状态信息。

不幸的是,这包括你想要做的事情。希望有一天MapKit将被扩展以允许这些功能......尽管不太可能。

好运。

+1

PRN不说他试图做任何事情或转弯转弯:只是他想覆盖方向。您可以使用Google Maps JavaScript API(我认为)这样做,但不能使用MapKit。你显然比我更熟悉Google API--如果它没有轮到我们,有什么办法可以获得道路向量? [看到这个问题让我感兴趣吧!] – Andiih 2010-05-15 06:51:30

+1

它不是轮流转,而是它的路线指引,不是吗? – Daniel 2012-04-13 18:19:39

5

你可能想看看https://github.com/leviathan/nvpolyline让该溶液在之前iPhone OS版本,特别是有针对性地V.4.0

虽然它也可以在4.0版希望这有助于使用。

+0

嗨柯林斯,都对不起延迟回复的 第一......但与上述的例子中,坐标是在应用程序中硬编码的,我想是拿到坐标作为被选择的位置和时......不是预先安装坐标的地方。例如,游客可以选择城市中的任意位置,并且应该根据他/她当前的坐标提供路线。此选定的位置坐标可能未预先加载。 – PRN 2010-07-29 06:19:44

+0

PRN请转到polyline GitHub项目并打开问题报告(http://github.com/mobilemelting/nvpolyline/issues)。我会尽力为您的问题整合一个解决方案。 – leviathan 2010-07-29 07:23:55

+0

正确的URL是https://github.com/leviathan/nvpolyline – leviathan 2012-01-10 22:54:17

3

MapQuest有一个SDK,它是MapKit的直接替代品。它目前处于测试阶段,但正在积极开发中。

它允许覆盖,路由和地理编码。

MapQuest iOS Maps API

3

只是为了澄清,它看起来像有正在讨论两件事情。一种是获取路线顶点的方法,另一种是使用这些顶点在地图上绘制覆盖图。我知道MapQuest的API,所以我有一些链接的谷歌和Bing有我认为的等值。

1)路线
如果你正在寻找一个路线的新坐标绘制的路线重叠,您可以使用Web服务调用路由Web服务的获取顶点 - 我假设你'在这里使用JavaScript来显示地图。如果您使用的是本地代码,您仍然可以访问Web服务,或者您可以使用本地调用(即MapQuest iPhone SDK具有本地路由调用)。

大多数路线服务应返回路线的“形状点”,以便绘制。

下面是使用MapQuest- 路线网络服务来获取shapepoints一些例子(见形状返回对象) - http://www.mapquestapi.com/directions/

2)绘制一个覆盖
一旦你有你的顶点,你需要吸引他们。我认为大多数JavaScript地图API都会有某种重叠类。这里的MapQuest的一个: http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/overlays#line

3)与一个呼叫做这
的MapQuest也有一些方便的功能,使呼叫路由和划清界线你 - 我不能发布两个以上的链路!因此,转到上面的链接并在左侧的导航栏中查找“路由”。

61

以下viewDidLoad将(1)设置两个位置,(2)删除所有前面的注释,以及(3)调用用户定义的帮助函数(获取路线点并绘制路线)。

-(void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // Origin Location. 
    CLLocationCoordinate2D loc1; 
    loc1.latitude = 29.0167; 
    loc1.longitude = 77.3833; 
    Annotation *origin = [[Annotation alloc] initWithTitle:@"loc1" subTitle:@"Home1" andCoordinate:loc1]; 
    [objMapView addAnnotation:origin]; 

    // Destination Location. 
    CLLocationCoordinate2D loc2; 
    loc2.latitude = 19.076000; 
    loc2.longitude = 72.877670; 
    Annotation *destination = [[Annotation alloc] initWithTitle:@"loc2" subTitle:@"Home2" andCoordinate:loc2]; 
    [objMapView addAnnotation:destination]; 

    if(arrRoutePoints) // Remove all annotations 
     [objMapView removeAnnotations:[objMapView annotations]]; 

    arrRoutePoints = [self getRoutePointFrom:origin to:destination]; 
    [self drawRoute]; 
    [self centerMap]; 
} 

以下是MKMapViewDelegate方法,吸引覆盖(iOS的4.0和更高版本)。

/* MKMapViewDelegate Meth0d -- for viewForOverlay*/ 
- (MKOverlayView*)mapView:(MKMapView*)theMapView viewForOverlay:(id <MKOverlay>)overlay 
{ 
    MKPolylineView *view = [[MKPolylineView alloc] initWithPolyline:objPolyline]; 
    view.fillColor = [UIColor blackColor]; 
    view.strokeColor = [UIColor blackColor]; 
    view.lineWidth = 4; 
    return view; 
} 

以下函数将获取位置和准备URL以获取所有路线点。当然,将会调用stringWithURL。

/* This will get the route coordinates from the Google API. */ 
- (NSArray*)getRoutePointFrom:(Annotation *)origin to:(Annotation *)destination 
{ 
    NSString* saddr = [NSString stringWithFormat:@"%f,%f", origin.coordinate.latitude, origin.coordinate.longitude]; 
    NSString* daddr = [NSString stringWithFormat:@"%f,%f", destination.coordinate.latitude, destination.coordinate.longitude]; 

    NSString* apiUrlStr = [NSString stringWithFormat:@"http://maps.google.com/maps?output=dragdir&saddr=%@&daddr=%@", saddr, daddr]; 
    NSURL* apiUrl = [NSURL URLWithString:apiUrlStr]; 

    NSError *error; 
    NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSUTF8StringEncoding error:&error]; 
    NSString* encodedPoints = [apiResponse stringByMatching:@"points:\\\"([^\\\"]*)\\\"" capture:1L]; 

    return [self decodePolyLine:[encodedPoints mutableCopy]]; 
} 

下面的代码是真正的魔术(我们从API获得的响应的解码器)。我不修改代码,除非我知道我在做什么:)

- (NSMutableArray *)decodePolyLine:(NSMutableString *)encodedString 
{ 
    [encodedString replaceOccurrencesOfString:@"\\\\" withString:@"\\" 
            options:NSLiteralSearch 
            range:NSMakeRange(0, [encodedString length])]; 
    NSInteger len = [encodedString 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 = [encodedString 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 = [encodedString 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("\n[%f,", [latitude doubleValue]); 
     printf("%f]", [longitude doubleValue]); 
     CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]]; 
     [array addObject:loc]; 
    } 
    return array; 
} 

此功能将以此为途径,将增加的覆盖。

- (void)drawRoute 
{ 
    int numPoints = [arrRoutePoints count]; 
    if (numPoints > 1) 
    { 
     CLLocationCoordinate2D* coords = malloc(numPoints * sizeof(CLLocationCoordinate2D)); 
     for (int i = 0; i < numPoints; i++) 
     { 
      CLLocation* current = [arrRoutePoints objectAtIndex:i]; 
      coords[i] = current.coordinate; 
     } 

     self.objPolyline = [MKPolyline polylineWithCoordinates:coords count:numPoints]; 
     free(coords); 

     [objMapView addOverlay:objPolyline]; 
     [objMapView setNeedsDisplay]; 
    } 
} 

以下代码将居中对齐地图。

- (void)centerMap 
{ 
    MKCoordinateRegion region; 

    CLLocationDegrees maxLat = -90; 
    CLLocationDegrees maxLon = -180; 
    CLLocationDegrees minLat = 90; 
    CLLocationDegrees minLon = 180; 

    for(int idx = 0; idx < arrRoutePoints.count; idx++) 
    { 
     CLLocation* currentLocation = [arrRoutePoints 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; 
    region.center.longitude = (maxLon + minLon)/2; 
    region.span.latitudeDelta = maxLat - minLat; 
    region.span.longitudeDelta = maxLon - minLon; 

    [objMapView setRegion:region animated:YES]; 
} 

我希望这会帮助别人。

+0

希望你的绘图路线方法正常工作。我使用了几乎相同的函数,就像你的decodePolyLine函数。我CLLocations的数组,但我之后卡住,因为该方法“polylineWithCordinates”采取CLLocationCordinate2D的arrray,我不知道怎么我的数组转换为CLLocationCordinate2D阵列。我明天将在我的工作场所尝试你的抽签方法。顺便说一句,你可以解释这一行'CLLocationCoordinate2D * coords = malloc(numPoints * sizeof(CLLocationCoordinate2D));' – Nil 2012-12-16 09:30:11

+1

@ rd4code CLLocationCoordinate2D * coords = malloc(numPoints * sizeof(CLLocationCoordinate2D));' - 它在内存中分配的块大小与我们的'arrRoutePoints'的大小相等,每个索引对象都是'CLLocationCoordinate2D'。希望你明白。 – viral 2012-12-17 04:47:12

+0

你的方法今天工作:)。谢谢你的解释。 。另外我想问问是否有另一种方式创建CLLocationCoordinate2D数组?我的意思是如果malloc是必要的? – Nil 2012-12-17 05:09:09

3

获取和在地图上绘制的路线与iOS 7 API超级简单:

MKDirectionsRequest *directionsRequest = [[MKDirectionsRequest alloc] init]; 

// Set the origin of the route to be current user location 
[directionsRequest setSource:[MKMapItem mapItemForCurrentLocation]]; 

// Set the destination point of the route 
CLLocationCoordinate2D destinationCoordinate = CLLocationCoordinate2DMake(34.0872, 76.235); 
MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoordinate addressDictionary:nil]; 
[directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:destinationPlacemark]]; 

MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest]; 

// Requesting route information from Apple Map services 
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { 
    if (error) { 
     NSLog(@"Cannot calculate directions: %@",[error localizedDescription]); 
    } else { 
     // Displaying the route on the map 
     MKRoute *route = [response.routes firstObject]; 
     [mapView addOverlay:route.polyline]; 
    } 
}]; 
+1

您如何为MapKit中没有方向支持的国家做同样的事情? – madLokesh 2015-03-09 08:35:53

2

要更新这个问题,就没有必要以来iOS7外部APK。

这里一个非常简单而有效的解决方案:

http://technet.weblineindia.com/mobile/draw-route-between-2-points-on-map-with-ios7-mapkit-api/2/

我知道这个问题是关于iOS 6的,但我相信这个解决方案将是有益的很多人。

在这种解决方案缺少的是执行以下的委托方法来显示起止销

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation