繁体   English   中英

iOS路径跟随:将坐标列表转换为贝塞尔曲线

[英]iOS path following: convert list of coordinates to a bezier curve

我有一个坐标数组,代表用户路线。 我希望能够重绘这条路线并让其他用户完全遵循它。 虽然我只想在路线改变方向时保存重要的坐标(航路点)。

有没有办法我可以将坐标数组转换为贝塞尔曲线并使用它,所以我只得到重要的坐标,而不是保存一个数组中的每一个(大多数是相同的方向,不需要)

我希望能够重建路线以提供航路点。 这些航路点将用于引导用户沿着路线前进,因为最终我将使用MKDirections将它们引导到每个航路点。

您不应该使用MKDirections,因为它不是为了遵循预先计算的路径而是为您提供到达目的地的最快路线! 因此我将改用MKMapOverlayRenderer!

有几件事你可以实现这一目标。 我想谈谈用于删除不必要的航路点的简单算法:

NSArray* path = YOURPATH
NSMutableArray* waypoints = [path mutableCopy];

CGFloat smoothness = 0.01;

for(NSInteger scale=1;scale<log2(waypoints.count);scale++)
{
    for(NSInteger index = 0; index<waypoints.count-2;index++)
    {
        CLLocation *start = [waypoints objectAtIndex:index];
        CLLocation *middle = [waypoints objectAtIndex:index+1];
        CLLocation *end = [waypoints objectAtIndex:index+2];

        CGFloat dist_start_end = [end distanceFromLocation:start];
        CGFloat dist_start_middle_end = [middle distanceFromLocation:start]+[end distanceFromLocation:middle];

        CGFloat diff = dist_start_end-dist_start_middle_end;
        CGFloat ratio = diff/(dist_start_end);

        if (ratio<1+smoothness) {
            [waypoints removeObjectAtIndex:index+1];
            index-=1;
        }
    }
}

这应该删除不需要的点。 您应该使用'smoothness'变量进行游戏。 值越大,删除的细节越多! (因此压缩效果更好)

现在使用此数组,您可以构建贝塞尔路径!

我不会详细介绍如何将bezier路径实际放到地图上,还有很多关于Stackoverflow的其他问题以及互联网上的教程。 但我将简要介绍如何创建/使用bezier路径的两个控制点:

给定我们上面创建的航点阵列,您可能会添加一些额外的控制点,以避免驾驶方向在建筑物中使用快捷方式。 因此,您应该计算路径上两个实际点之间的控制点,如下所示:

CGFloat cornerRadius = 5;
NSMutableArray* pathPoints = [NSMutableArray new];

if (waypoints.count>1) {
    [pathPoints addObject:[waypoints objectAtIndex:0]];
    [pathPoints addObject:[waypoints objectAtIndex:0]];
    [pathPoints addObject:[waypoints objectAtIndex:1]];
    [pathPoints addObject:[waypoints objectAtIndex:1]];
}
for (NSInteger index = 1;index<waypoints.count-1;index++) {
    CLLocation* lastLocation = [waypoints objectAtIndex:index-1];
    CLLocation* currentLocation = [waypoints objectAtIndex:index];
    CLLocation* nextLocation = [waypoints objectAtIndex:index+1];

    [pathPoints addObject:currentLocation];

    CGFloat latDiff = currentLocation.coordinate.latitude - lastLocation.coordinate.latitude;
    CGFloat longDiff = currentLocation.coordinate.longitude - lastLocation.coordinate.longitude;
    CGFloat dist = [currentLocation distanceFromLocation:lastLocation];
    CGFloat controlPointALat = cornerRadius*latDiff/dist;
    CGFloat controlPointALong = cornerRadius*longDiff/dist;

    CLLocation* controlPointA =
    [[CLLocation alloc] initWithLatitude:controlPointALat longitude:controlPointALong];
    [pathPoints addObject:controlPointA];

    if (index<waypoints.count-2) {
        CLLocation* nextNextLocation = [waypoints objectAtIndex:index+2];

        latDiff = nextNextLocation.coordinate.latitude - nextLocation.coordinate.latitude;
        longDiff = nextNextLocation.coordinate.longitude - nextLocation.coordinate.longitude;
        dist = [nextNextLocation distanceFromLocation:nextLocation];
        CGFloat controlPointBLat = cornerRadius*latDiff/dist;
        CGFloat controlPointBLong = cornerRadius*longDiff/dist;

        CLLocation* controlPointB =
        [[CLLocation alloc] initWithLatitude:controlPointBLat longitude:controlPointBLong];
        [pathPoints addObject:controlPointB];
    }else{
        [pathPoints addObject:controlPointA];
    }
    [pathPoints addObject:nextLocation];
}

现在,您可以使用此pathArray通过简单的for循环构建bezierPaths:

for(NSInteger index=0;index<pathPoints.count-3;index+=4)
{
   CLLocation *start = [pathPoints objectAtIndex:index];
   CLLocation *controlPointA = [pathPoints objectAtIndex:index+1];
   CLLocation *controlPointB = [pathPoints objectAtIndex:index+2];
   CLLocation *end = [pathPoints objectAtIndex:index+3];

   //BEZIER CURVE HERE
}

您可以使用UIBezierPath并使用CGPath属性来创建MKMapOverlayRenderer,也可以直接使用CGPath。 稍后将添加路径到地图: MKMapOverlayRenderer

此处描述了创建UIBezierPath: UIBezierPath

您可以使用NSValues数组,因为您无法将CGPoint直接添加到数组中

这是我们的做法

NSMutableArray *arrayOfPoints = [[NSMutableArray alloc] init];
[arrayOfPoints addObject:[NSValue valueWithCGPoint:CGPointMake(10, 20)]];
// here point is the cgpoint you want to add 

现在,您已将点添加到数组中,您可以执行的操作是遍历每个对象并将它们添加到UIBezierPath

  NSInteger  i = 0;
   UIBezierPath _path1 = [UIBezierPath bezierPath];

for(NSValue *val in arrayOfPoints){
    if (i==0){
        [_path1 moveToPoint:[val CGPointValue]];
    }
    else{
        [_path1 addLineToPoint:[val CGPointValue]];
    }
    i++;
}

我希望这有助于解决您的问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM