2014-03-12 5 views
0

사용자 경로를 나타내는 좌표 배열이 있습니다. 이 경로를 다시 그리고 다른 사용자가 정확히 따라갈 수 있기를 원합니다. 경로가 방향을 바꿀 때 중요한 좌표 (경유 점) 만 저장하려고합니다.iOS 경로 다음 : 좌표 목록을 베 지어 곡선으로 변환

좌표 배열을 베 지어 곡선으로 변환하고이를 사용하여 배열에 하나씩 저장하는 대신 중요한 좌표만을 얻는 방법이 있습니까 (대부분은 같은 방향이고 필요하지 않습니다).)

나는 경유지를 제공하기 위해 경로를 재구성 할 수 있기를 원합니다. 이 웨이 포인트는 결국 경로를 따라 사용자를 안내하는 데 사용되어 MKDirections를 사용하여 각 웨이 포인트로 안내합니다. 당신이 배열

에 직접 CGPoint를 추가 할 수 있기 때문에

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

이것은 원하지 않는 점을 제거해야합니다. 'smoothness'변수로 playaround를해야합니다. 값이 클수록 더 많은 세부 사항이 제거됩니다! (따라서 더 나은 압축)

이제이 배열을 사용하여 베 지어 경로를 구성 할 수 있습니다!

지도에 베 지어 경로를 실제로 두는 방법에 대한 세부 정보는 들어 가지 않습니다. Stackoverflow 및 인터넷 자습서에 대한 다른 많은 질문이 있습니다. 그러나 베 지어 경로의 두 조절 점을 어떻게 만들고 사용해야하는지 잠시 만질 것입니다 :

우리가 위에서 작성한 중간 점 배열을 감안할 때, 운전 방향을 피하기 위해 추가 제어점을 추가 할 것입니다. 건물을 지름길. 하나

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 
} 

당신은 할 수 있습니다

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

은 이제 간단한 for 루프와 bezierPaths를 구축하기 위해이 pathArray를 사용할 수 있습니다 따라서이 같은 경로에 두 개의 실제 지점 사이 제어점을 계산한다 UIBezierPath를 사용하고 CGPath 속성을 사용하여 MKMapOverlayRenderer를 만들거나 직접 CGPath를 사용할 수 있습니다.나중에지도에 경로를 추가하는 것은 여기에 설명하십시오 UIBezierPath를 Createing 이 MKMapOverlayRenderer

여기에 설명되어 있습니다 : UIBezierPath

+0

답해 주셔서 감사합니다. 나는 여전히 MKDirections가 필요하다고 생각한다. 경로상의 최종 위치가 아니라 사용자가 현재 위치에서 다음 중요한 지점으로가는 길을 안내한다. – Sarah92

+1

첫 번째 코드 조각에 대해 index- = 1; ~위한거야? – Sarah92

+0

Thx, @ Sarah92 그것은 brakets 안에 있어야하는데, 나는 그것을 바 꾸었습니다! 이제는 필요한 경우 여러 점을 제거 할 수 있습니다. –

0

당신이 우리가

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

지금 당신은 당신의 포인트 배열에 추가 할 어떻게 NSValues의 배열을 수행 할 수있는 할 수있는 당신은 모든 객체를 통과하고이 도움이

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

내가 희망 당신 UIBezierPath에 추가하고 문제를 해결할 수있다

,
+0

이것은 베 지어 경로가 아니라 회선 경로를 생성합니다 –