【问题标题】:Check user is following the route or not (iphone)检查用户是否遵循路线(iphone)
【发布时间】:2013-03-13 03:50:07
【问题描述】:

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

为了计算路线我使用了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];


}

到目前为止,一切都很好。

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

问题:~ 如果道路是直的(超过 100 公吨),那么我无法在道路上得分。为了解释问题,我附上了图片...

在这张图片中,假设黑线是我的路径(折线),红色圆圈是我从 google api 获得的点。但是在显示为蓝色圆圈的直线路径中,我无法获得要比较的点,并且在此路径中调用了重新计算函数。

谁能告诉我解决方案,我可以从中获得所有路线点,即使它是一条笔直的道路。

【问题讨论】:

  • 通常 google api 返回关节上的多边形点,或者,曲线不在直线路径上,它将给出直线路径的起点和终点..
  • 这就是 iphonic 的问题。 OP在大于100m时需要一些沿直线的中间点
  • 在这种情况下,您可以找出点之间的距离平均值,如果超过任何点之间的距离,则输入用户位置..
  • 谢谢大家,但我不知道如何在起点和终点之间获得多边形

标签: iphone ios mkmapview polyline map-directions


【解决方案1】:

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

  1. 计算当前位置到地图中所有点的距离 MKPolyline 并从中获取最小值。 (可能有一些很好的方法来优化它。比如不迭代每次位置更新时的所有点,但现在没有时间深入研究)。
  2. 您现在知道到最近的折线点的距离。但是,该点可能仍然很远,而折线本身(连接该点和上一个或下一个点)可能更近。因此,计算您当前位置与这两个线段之间的距离,您就有了最近的距离。

现在,这不是防水的。虽然它最大限度地减少了 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.
    }
}

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

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

}

【讨论】:

  • 我在 KM 中得到的结果好坏参半,似乎有些奇怪。我也不明白最后 lineSegmentDistanceFromOrigin 的 * 100。你能解释一下吗?
  • 嗨 Sjoerd。你能详细说明混合的结果吗?你的意思是?老实说,我不记得为什么是100。可能是我想要 100 米的结果。不确定。最好自己对此进行一些测试,以确定您从该方法中获得的单位。
  • 我将此函数与 CLLocation 上的 distanceFromLocation 与两点进行了比较。由于某种原因,我不能总是得到好的结果。我现在切换到另一个使用 MKMapPoints 并获得更好结果的解决方案:stackoverflow.com/questions/26240183/… - 感谢您的回复!
  • 想在我的应用程序中使用相同的功能,但没有得到解决方案可以帮助我们
【解决方案2】:

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

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

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

【讨论】:

  • 感谢您的回答。但我是地图新手。那么您能否解释一下如何沿线段获取中间点。
  • 感谢我通过画线算法获得了所有分数。但是我又遇到了一个问题请看THIS QUESTION请帮帮我
猜你喜欢
  • 2012-09-06
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 2021-05-18
  • 2016-06-07
  • 1970-01-01
  • 2016-04-22
  • 2020-09-27
相关资源
最近更新 更多