2013-03-23 74 views
2

我正在制作一个基于导航的应用程序。在这个应用程序中,我正在从用户选择的点绘制路线。如果用户没有遵循路线,我有重新计算路线的要求。检查用户是否遵循路线(iphone)

用于计算我已使用的路线Google direction API。并绘制我使用此代码的路线

- (void) drawRoute:(NSArray *) path 
{ 
    NSInteger numberOfSteps = path.count; 
    [self.objMapView removeOverlays: self.objMapView.overlays]; 

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

     coordinates[index] = coordinate; 
    } 

    for(id <MKOverlay> ovr in [self.objMapView overlays]) 
    { 
     MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:ovr]; 


     if (polylineView.tag == 22) 
     { 
      [self.objMapView removeOverlay:ovr]; 
     } 
     [polylineView release]; 
    } 

    MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps]; 
    [self.objMapView addOverlay:polyLine]; 


} 

直到现在,每件事情都是okey。

现在,我希望有一个通知,如果用户外出路线(超过100米)的。而我能得到通知还

问题:〜如果道路是直线道路(超过100吨以上),那么我不能让点在路上。为了说明我重视形象问题......

ROUTE

在此图像中假设黑线是我的路(折线)和红色圆圈是我得到了谷歌的形式的API的点。但在直线路径显示为蓝色的圆形我不能得到点进行比较,并在此路径中重新计算函数被调用。

任何人都可以告诉我解决方案,即使它是直路,我也可以获得所有路线点。

+0

通常谷歌API返回关节或曲线聚点不是直线路径上,它会给起点和终点的直线路径.. – iphonic 2013-03-23 08:29:40

+0

这就是问题所在iphonic。当OP大于100米时需要沿着一条直线的一些中间点。 – 2013-03-23 08:30:39

+0

在这种情况下,您可以找出点之间的距离的平均值,如果它超过任何点之间,放置用户的位置.. – iphonic 2013-03-23 08:42:52

回答

3

我知道这是一个旧的线程,但最近遇到了同样的问题,并找到了一个好的解决方案。 这个概念是,您不计算到每条线段的距离,但只计算连接到最近点的两个线段。

  1. 计算您当前位置到 MKPolyline中所有点的距离,并取其最小值。 (可能有一些不错的方法来优化这个,就像不是遍历每个位置更新中的所有点,但是没有时间去挖掘它)。
  2. 您现在知道距离最近的折线点的距离。然而,这一点可能仍然很远,而折线本身(连接这一点与上一点或下一点)可能更接近。因此,计算您当前位置和这两条线段之间的距离,并且距离最近。

现在,这不是防水的。虽然它最大限度地减少了api调用次数,但在某些情况下(如果在MKPolyline中有疯狂的弯曲和曲线),它可能会在不需要的时候调用api,但是,嘿,然后再次绘制同一行,不会造成任何损害。在我的测试中,它工作正常,你也可以调整精度。我在下面的代码中将它设置为200米(0.2公里)。

//Get Coordinates of points in MKPolyline 
NSUInteger pointCount = routeLineGuidanceTurn.pointCount; 
CLLocationCoordinate2D *routeCoordinates = malloc(pointCount * sizeof(CLLocationCoordinate2D)); 
[routeLineGuidanceTurn getCoordinates:routeCoordinates 
         range:NSMakeRange(0, pointCount)]; 
NSLog(@"route pointCount = %d", pointCount); 


//Determine Minimum Distance and GuidancePoints from 
double MinDistanceFromGuidanceInKM = 1000; 
CLLocationCoordinate2D prevPoint; 
CLLocationCoordinate2D pointWithMinDistance; 
CLLocationCoordinate2D nextPoint; 

for (int c=0; c < pointCount; c++) 
{ 
    double newDistanceInKM = [self distanceBetweentwoPoints:Currentcordinate.latitude longitude:Currentcordinate.longitude Old:routeCoordinates[c].latitude longitude:routeCoordinates[c].longitude]; 
    if (newDistanceInKM < MinDistanceFromGuidanceInKM) { 
     MinDistanceFromGuidanceInKM = newDistanceInKM; 
     prevPoint = routeCoordinates[MAX(c-1,0)]; 
     pointWithMinDistance = routeCoordinates[c]; 
     nextPoint = routeCoordinates[MIN(c+1,pointCount-1)]; 
    } 
} 
free(routeCoordinates); 


NSLog(@"MinDistanceBefore: %f",MinDistanceFromGuidanceInKM); 

//If minimum distance > 200m we might have to recalc GuidanceLine. 
//To be sure we take the two linesegments connected to the point with the shortest distance and calculate the distance from our current position to that linedistance. 
if (MinDistanceFromGuidanceInKM > 0.2) { 
    MinDistanceFromGuidanceInKM = MIN(MIN([self lineSegmentDistanceFromOrigin:Currentcordinate onLineSegmentPointA:prevPoint pointB:pointWithMinDistance], [self lineSegmentDistanceFromOrigin:Currentcordinate onLineSegmentPointA:pointWithMinDistance pointB:nextPoint]),MinDistanceFromGuidanceInKM); 

    if (MinDistanceFromGuidanceInKM > 0.2) { 
     // Call the API and redraw the polyline. 
    } 
} 

这是计算两点之间距离的乐趣。我知道它有一个内置的函数,但它已经在我的代码中。

-(double)distanceBetweentwoPoints:(double)Nlat longitude:(double)Nlon Old:(double)Olat longitude:(double)Olon { 
    //NSLog(@"distanceBetweentwoPoints"); 
    double Math=3.14159265; 
    double radlat1 = Math* Nlat/180; 
    double radlat2 = Math * Olat/180; 
    double theta = Nlon-Olon; 
    double radtheta = Math * theta/180; 
    double dist = sin(radlat1) * sin(radlat2) + cos(radlat1) * cos(radlat2) * cos(radtheta); 
    if (dist>1) {dist=1;} else if (dist<-1) {dist=-1;} 
    dist = acos(dist); 
    dist = dist * 180/Math; 
    dist = dist * 60 * 1.1515; 
    return dist * 1.609344; 
} 

这里是计算一个点和另一个点之间的线段之间的距离的位。我从这里得到了这个:https://stackoverflow.com/a/28028023/3139134修改了一下,使用CLLocationCoordinate2D并返回距离。

- (CGFloat)lineSegmentDistanceFromOrigin:(CLLocationCoordinate2D)origin onLineSegmentPointA:(CLLocationCoordinate2D)pointA pointB:(CLLocationCoordinate2D)pointB { 

    CGPoint dAP = CGPointMake(origin.longitude - pointA.longitude, origin.latitude - pointA.latitude); 
    CGPoint dAB = CGPointMake(pointB.longitude - pointA.longitude, pointB.latitude - pointA.latitude); 
    CGFloat dot = dAP.x * dAB.x + dAP.y * dAB.y; 
    CGFloat squareLength = dAB.x * dAB.x + dAB.y * dAB.y; 
    CGFloat param = dot/squareLength; 

    CGPoint nearestPoint; 
    if (param < 0 || (pointA.longitude == pointB.longitude && pointA.latitude == pointB.latitude)) { 
     nearestPoint.x = pointA.longitude; 
     nearestPoint.y = pointA.latitude; 
    } else if (param > 1) { 
     nearestPoint.x = pointB.longitude; 
     nearestPoint.y = pointB.latitude; 
    } else { 
     nearestPoint.x = pointA.longitude + param * dAB.x; 
     nearestPoint.y = pointA.latitude + param * dAB.y; 
    } 

    CGFloat dx = origin.longitude - nearestPoint.x; 
    CGFloat dy = origin.latitude - nearestPoint.y; 
    return sqrtf(dx * dx + dy * dy) * 100; 

} 
+0

我在KM中得到混合结果似乎有些奇怪。我也不明白在结束lineSegmentDistanceFromOrigin * 100。你能解释一下吗? – 2015-12-24 09:18:02

+0

嗨Sjoerd。你能否详细说明混合结果?你什么意思?我真的不记得为什么100。可能是我想要100米的结果。不确定。最好自己做一些测试,以确定你从方法中获得的单位。 – guido 2015-12-25 13:40:52

+0

我将此函数与CLLocation上的distanceFromLocation与两点进行了比较。出于某种原因,我无法获得任何结果。我现在切换到另一个使用MKMapPoints并获得更好结果的解决方案:http://stackoverflow.com/questions/26240183/how-to-determine-the-next-poi-in-a-navigation-route - 感谢您的回复! – 2015-12-26 12:32:23

2

对于在每个步骤中的每对点,则可以使用勾股定理计算它们之间的距离:

distance = sqrt( pow((point1.x - point2.x), 2) + pow((point1.y - point2.y), 2) ) 

然后,如果该距离大于100m,沿着线段添加中介点。

+0

感谢您的答案。但我对地图很陌生。那么你能否解释一下如何获得沿线的中介点。 – 2013-03-23 08:49:14

+0

谢谢,我通过画线算法得到了所有的点。 但我遇到了一个问题,请参阅[这个问题](http://stackoverflow.com/questions/15585711/draw-poly-line-on-the-read-in-mkmap-view-iphone)请帮助我 – 2013-03-23 10:42:37