2014-03-12 47 views
0

我有一個表示用戶路線的座標數組。我希望能夠重新繪製這條路線,並讓另一個用戶完全遵循它。雖然我只想在路線改變方向時保存重要的座標(航點)。iOS路徑如下:將座標列表轉換爲貝塞爾曲線

有沒有一種方法可以將座標數組轉換成貝塞爾曲線並使用它,因此我只獲取重要的座標而不是將每個數據保存在一個數組中(其中大部分座標都是相同的方向,並且不需要)

我想能夠重建路線給路標。這些航點將被用來引導用戶沿着路線行駛,因爲最終我將使用MKDirections將它們引導到每個航點。

+1

的可能重複[繪製平滑的曲線 - 方法需要](http://stackoverflow.com/questions/8702696/drawing-smooth-curves-methods-needed) – Caleb

回答

2

您不應該使用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; 
     } 
    } 
} 

這應該刪除不需要的點。你應該用'平滑'變量來調整。價值越大,更多的細節將被刪除! (因此更好的壓縮)

現在用這個數組,你可以構建你的貝塞爾路徑!

我不會詳細討論如何實際將貝塞爾路徑放置到地圖上,關於Stackoverflow和Internet上的教程還有很多其他問題。但是我會很快談談你應該如何創建/使用bezier路徑的兩個控制點:

給定我們上面創建的waypoints數組,你可能會添加一些額外的控制點,以避免駕駛方向需要通過建築物的捷徑。因此,你應該像這樣的路徑上兩個實際點之間計算控制點:

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建立你bezierPaths用一個簡單的for循環:

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

Createing一個UIBezierPath這裏描述: UIBezierPath

+0

感謝您的回答。我仍然認爲我需要MKDirections,而不是路線上的最終位置..但是讓用戶從他們當前的位置指向下一個重要點。 – Sarah92

+1

我可以要求第一段代碼是什麼index- = 1;是爲了? – Sarah92

+0

Thx,@ Sarah92它應該在腳架內,我改變了!現在它允許刪除多個點,如果需要 –

0

您可以NSValues數組,因爲你不能直接添加一個CGPoint爲Array

這是我們如何做到這一點

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++; 
} 

我希望這有助於解決您的問題

+0

這不會創建貝塞爾路徑,而只是一條線路徑 –