2016-06-05 4 views
1

여기에 무슨 일이 있습니다 : 그릴 때 베 지어 선은 매우 매끄 럽습니다. 부드러움을 가능하게 만들기 위해 제어점과 끝점을 만드는 개념을 적용했습니다. 그러나 나는 그 래그를 일으키는 문제를 발견 할 수 없다.베 지어 커브 그리기가 매우 느립니다.

그릴 때 CPU 사용량을 확인하고 5 초 후 약 50 %에서 90 %로 변경됩니다. 나는 드로잉을 마쳤을 때 점을 지우고 버퍼를 사용하여 내가 그렸던 것을 이미지로 만듭니다.

내 생각에 너무 많은 점이 동시에 터치로 그려져 있습니다 .Moved? 프로그램이 처리하기에는 너무 많은 부분이있을 수 있습니다.

#import "SmoothedBIView.h" 

@implementation SmoothedBIView 
{ 
    UIBezierPath *path; 
    UIImage *incrementalImage; 
    CGPoint pts[5]; // need to keep track of the four points of a Bezier segment and the first control point of the next segment 
    uint ctr; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    if (self = [super initWithCoder:aDecoder]) 
    { 
     [self setMultipleTouchEnabled:NO]; 
     [self setBackgroundColor:[UIColor whiteColor]]; 
     path = [UIBezierPath bezierPath]; 
     [path setLineWidth:2.0]; 
    } 
    return self; 

} 
/* - (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     [self setMultipleTouchEnabled:NO]; 
     path = [UIBezierPath bezierPath]; 
     [path setLineWidth:2.0]; 
    } 
    return self; 
} 
*/ 


animation. 
- (void)drawRect:(CGRect)rect 
{ 
    [incrementalImage drawInRect:rect]; 
    [path stroke]; 
} 


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    ctr = 0; 
    UITouch *touch = [touches anyObject]; 
    pts[0] = [touch locationInView:self]; 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint p = [touch locationInView:self]; 
    ctr++; 
    pts[ctr] = p; 
    if (ctr == 4) 
    { 
     pts[3] = CGPointMake((pts[2].x + pts[4].x)/2.0, (pts[2].y + pts[4].y)/2.0); // move the endpoint to the middle of the line joining the second control point of the first Bezier segment and the first control point of the second Bezier segment 

     [path moveToPoint:pts[0]]; 
     [path addCurveToPoint:pts[3] controlPoint1:pts[1] controlPoint2:pts[2]]; // add a cubic Bezier from pt[0] to pt[3], with control points pt[1] and pt[2] 

     [self setNeedsDisplay]; 
     // replace points and get ready to handle the next segment 
     pts[0] = pts[3]; 
     pts[1] = pts[4]; 
     ctr = 1; 
    } 

} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [self drawBitmap]; 
    /*[self setNeedsDisplay]; */ 
    [path removeAllPoints]; 
    ctr = 0; 
} 

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [self touchesEnded:touches withEvent:event]; 
} 

- (void)drawBitmap 
{ 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0); 

    if (!incrementalImage) 
    { 
     UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; 
     [[UIColor whiteColor] setFill]; 
     [rectpath fill]; 
    } 
    [incrementalImage drawAtPoint:CGPointZero]; 
    [[UIColor blackColor] setStroke]; 
    [path stroke]; 
    incrementalImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
} 

@end 
+0

지연 (lag)이라고 할 때, 일정한 지연을 언급하고 있습니까? (알고리즘의 자연스런 결과로 매 4 번째 포인트 만 그립니다)? 아니면 (사용자가 제스처가 완료되었을 때만 이미지 스냅 샷을 다시 작성하기 때문에) 사용자가 손가락을 쥐고있을 때 점점 길어질 지연을 말하는 것입니까? 두 가지 문제는 모두 여기에 있지만, 나는 당신이 어떤 말을하고 있는지 확신 할 수 없다. – Rob

+0

'CGPath'와'CGImage'로 전환하는 것이 당신이 측정하지 않는 한 말하기가 더 효율적 이겠지요. – ColdSteel

+0

@Rob 이것은 일정한 지체입니다. –

답변

1

몇 가지 문제는 여기에 있습니다 :

이 알고리즘을 앓고있는 일정 지연이 염려되는 경우
  1. , 하나의 문제는 당신의 카운터가있는 경우에만 당신이 경로를 업데이트하는 것입니다 4 (그리고 당신은 항상 적어도 한 점을 지키고 있습니다), 이는 과장을 과장 할 것입니다. 여기서 설명한대로 경로를 더 자주 업데이트 할 수 있습니다. https://stackoverflow.com/a/34997902/1271826은 사용자의 것과 매우 유사한 Swift 구현입니다.

    기본적 아이디어는 카운터가 4를 때릴 때까지 기다리지 않고 카운터가 1 일 때 선을 그리고 카운터가 2 일 때 쿼드 커브를 그리고 카운터가 3 일 때 3 차 곡선을 그리고, 카운터가 4 일 때 개정 된 3 차 곡선을 그립니다. 그러면 알고리즘에 영향을주는 일반적인 지연이 줄어 듭니다.

  2. 예기치 않은 느낌을 사용하여 느껴지는 지체를 줄일 수 있습니다. 문제를 풀지는 못하지만 알고리즘이 조금 복잡해집니다. 실제 접촉이 마침내 시작될 때 이전에 예측 된 접촉을 취소해야한다는 개념을 고려해야하기 때문입니다. 그러나 인식 지연을 훨씬 더 낮게 유지합니다. 예측 접촉 (Catmull-Rom 및 Hermite 스플라인과 함께 다른 평활화 알고리즘과 함께 사용)을 사용하는 방법의 예는 https://stackoverflow.com/a/34583708/1271826을 참조하십시오. Swift 레퍼런스에 대해 사과드립니다. 그러나 Objective-C에 대한 예지 적 검색을 검색하면 많은 예제를 찾을 수있을 것으로 생각됩니다.

  3. 스냅 샷을 생성하기 전에 터치가 끝날 때까지 기다리는 것이 아니라 베 지어가 너무 길어 지므로 지연이 걱정되는 경우 제스처의 중간에 터치해도 고정 된 횟수만큼 수행하십시오. 이렇게하면 베 지어가 너무 오래 지쳐 성능 문제가 발생하지 않게됩니다. 네, 드로잉 제스처의 중간에서 계산적으로 집중적 인 작업을하지는 않겠지 만, 어느 시점에서는 선을 그려야합니다.

  4. 직접 그리기보다는 베 지어 경로에 CAShapeLayer을 사용하는 데 대한 인수가 있습니다. 나는 이것이 단순한 drawRect 구현보다 더 최적화되었다는 것을 보았지만, 결코 벤치마킹 한 적이 없다고 고백한다.

0

성능면에서 쉬운 승리는 setNeedsDisplay 대신 setNeedsDisplayInRect :를 사용하는 것입니다. 현재 변경된 영역이 아닌 전체보기를 다시 그려야합니다.

+0

베 지어 커브의 경우 매개 변수에 넣을 점을 파악하는 데 어려움을 겪었습니다. setNeedsDisplayInRect는 내가 아는 바로 정상적인 포인트로 작동합니다. –

+0

커브는 2 개의 끝점과 2 개의 조절 점으로 정의 된 상자 안에 완전히 그려집니다. 그래서 minX = MIN (a.x, b.x, c1.x, c2.x), minY = MIN (a.y, b.y, c1.y, c2.y), maxX = 등등. 베 지어는 곡선의 중간에서 스트로크하므로 선 너비의 버퍼를 추가 할 수 있습니다. –