: convert list of coordinates to a bezier curve 之后的 iOS 路径

标签 ios objective-c uibezierpath cllocation bezier

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

有没有一种方法可以将坐标数组转换为贝塞尔曲线并使用它,这样我就只能得到重要的坐标,而不是将每个坐标都保存在数组中(其中大部分都在同一方向,不需要)

我希望能够重建路线以提供路标。这些路标将用于引导用户沿着路线前进,因为最终我将使用 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;
        }
    }
}

这应该会删除不需要的点。您应该尝试使用“平滑度”变量。值越大,去除的细节越多! (因此更好的压缩)

现在有了这个数组,您就可以构建贝塞尔曲线路径了!

我不会详细介绍如何实际将贝塞尔路径放到 map 上,在 Stackoverflow 上还有很多其他关于此的问题以及互联网上的教程。但我将很快谈到您应该如何创建/使用贝塞尔曲线路径的两个控制点:

鉴于我们在上面创建的航路点数组,您可能会添加一些额外的控制点,以避免驾车路线走捷径穿过建筑物。因此,您应该像这样计算路径上两个实际点之间的控制点:

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。稍后将路径添加到您的 map 如下所述: MKMapOverlayRenderer

此处描述了如何创建 UIBezierPath: UIBezierPath

关于: convert list of coordinates to a bezier curve 之后的 iOS 路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22354140/

相关文章:

swift - 每个角都有不同的 CornerRadius 到 Border

ios - 如何从 URI 获取文件 |博览会 | react native

java - 如何在不定义新类的情况下在 Swift 中实现 Objective-C

objective-c - 旋转和捏合(缩放)手势会扰乱父 UIView 及其 subview 框架

objective-c - 使用内部阴影的 UILabel 中的发光效果

objective-c - 制作 UIBezierPath 的独立副本?

swift - 部分 UIView 的屏幕截图被屏蔽为 UIBezierPath/CGPath

objective-c - 如何在ScrollView中实现动态UITTableViews,动态量为 'pages'

ios - 如何更改 iOS 7.1.1/iPhone 5s 上的导航栏按钮颜色

ios - 适用于 iOS 的 AWS DynamoDB 字符串属性返回 nil