检查用户是否遵循路线(iphone)

检查用户是否遵循路线(iphone),iphone,ios,mkmapview,polyline,map-directions,Iphone,Ios,Mkmapview,Polyline,Map Directions,我正在制作一个基于导航的应用程序。在此应用程序中,我从用户选择的点绘制路线。我有重新计算路线的要求,如果用户没有遵循路线 为了计算路线,我使用了googledirectionapi。为了画路线,我用了这个代码 - (void) drawRoute:(NSArray *) path { NSInteger numberOfSteps = path.count; [self.objMapView removeOverlays: self.objMapView.overlays];

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

为了计算路线,我使用了
googledirectionapi
。为了画路线,我用了这个代码

- (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];


}
-(void)绘图路线:(NSArray*)路径
{
NSInteger numberOfSteps=path.count;
[self.objMapView removeOverlays:self.objMapView.overlays];
CLLocationCoordinate2D坐标[步数];
对于(NSInteger index=0;index
到目前为止,一切都很顺利

现在,如果用户不在路线上(超过100米),我需要一个通知。我也可以得到通知

问题:~如果道路笔直(超过100公吨),我就无法在道路上获得积分。为了解释问题,我附上了图片

在这幅图中,假设黑线是我的路径(多段线),红圈是我从谷歌API中得到的点。但是在以蓝色圆圈显示的直线路径中,我无法获得要比较的点,并且在此路径中调用了重新计算函数


有谁能告诉我,哪怕是一条直线,我也能从中得到路线的所有点。

对于每一步中的每一对点,你可以使用毕达哥拉斯定理计算它们之间的距离:

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

然后,如果距离大于100m,则沿线段添加中间点。

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

  • 计算当前位置到图形中所有点的距离 MKPolyline并从中取最小值。(可能有一些很好的方法可以优化它。比如不要在每次位置更新时遍历所有点,但现在没有时间深入研究)
  • 现在您知道到最近多段线点的距离。但是,该点可能仍然很远,而多段线本身(连接该点和上一个或下一个点)可能更近。因此,计算当前位置与这两条线段之间的距离,就得到了最近的距离
  • 这不是防水的。虽然它最小化了api调用的nr,但在某些情况下(如果MKPolyline中有疯狂的折弯和曲线),它可能会在不需要时调用api,但是嘿,然后会再次绘制相同的线,不会造成任何损坏。在我的测试中,它工作得很好,你也可以调整精度。我在下面的代码中将其设置为200m(0.2km)

    //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.
        }
    }
    
    //获取MKPolyline中点的坐标
    NSUInteger pointCount=routeLineGuidanceTurn.pointCount;
    CLLocationCoordinate2D*routeCoordinates=malloc(pointCount*sizeof(CLLocationCoordinate2D));
    [RouteLineGuideDanceTurn getCoordinates:routeCoordinates
    范围:NSMakeRange(0,点计数)];
    NSLog(@“路由点计数=%d”,点计数);
    //确定距离的最小距离和引导点
    来自GuidanceInk的双思维距离=1000;
    CLLOCATIONCoordination2D前置点;
    CLLOCATION将2D点与MindDistance进行协调;
    CLLocationCoordination2D下一点;
    对于(int c=0;c200米,我们可能必须重新确定制导线。
    //为确保获得连接到距离最短点的两条线段,并计算从当前位置到该线距离的距离。
    if(MindDistanceFromGuidanceInkM>0.2){
    MindDistanceFromGuidanceInkM=MIN(MIN([自线段距离原点:当前自线段距离原点A:上一点B:带MindDistance的点],[自线段距离原点:当前自线段距离原点A:带MindDistance的点B:下一点]),MindDistanceFromGuidanceInkM);
    if(MindDistanceFromGuidanceInkM>0.2){
    //调用API并重新绘制多段线。
    }
    }
    
    下面是计算两点之间距离的乐趣。我知道它有一个内置函数,但我的代码中已经有了它

    -(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;
    }
    
    -(双)两点之间的距离:(双)Nlat经度:(双)Nlon Old:(双)Olat经度:(双)Olon{
    //NSLog(“两点之间的距离”);
    双重数学=3.14159265;
    双radlat1=数学*Nlat/180;
    双radlat2=数学*Olat/180;
    双θ=Nlon-Olon;
    双radtheta=数学*θ/180;
    双距离=sin(radlat1)*sin(radlat2)+cos(radlat1)*cos(radlat2)*cos(radtheta);
    
    如果(dist>1){dist=1;}如果(dist=1;}如果(dist)正常情况下,google api返回关节或曲线上的多边形点,而不是直线路径上的多边形点,它将给出直线路径的起点和终点..这就是IPhone的问题。OP需要
    - (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;
    
    }