我們不得不看你如何構建UIBezierPath
,但以我的經驗,爲流暢的曲線,關鍵的問題是,是否該線的曲線的控制點和特定區段的結束點之間的斜率的曲線等於曲線起點下一段與其控制點之間的斜率。我發現使用addCurveToPoint
而不是addQuadCurveToPoint
可以更容易地繪製一般smogooth曲線,以便我可以更一般地調整起始和結束控制點以滿足此準則。
爲了說明這一點,我通常繪製UIBezierPath
曲線的方式是在曲線上有一個點陣列,曲線在該點應該採取的角度,然後控制點的「權重」 (即控制點應該有多遠)。因此,我使用這些參數來指定UIBezierPath
的第二個控制點和UIBezierPath
的下一個段的第一個控制點。因此,舉例來說:
@interface BezierPoint : NSObject
@property CGPoint point;
@property CGFloat angle;
@property CGFloat weight;
@end
@implementation BezierPoint
- (id)initWithPoint:(CGPoint)point angle:(CGFloat)angle weight:(CGFloat)weight
{
self = [super init];
if (self)
{
self.point = point;
self.angle = angle;
self.weight = weight;
}
return self;
}
@end
然後,我如何使用這樣的例子:
- (void)loadBezierPointsArray
{
// clearly, you'd do whatever is appropriate for your chart.
// this is just a unclosed loop. But it illustrates the idea.
CGPoint startPoint = CGPointMake(self.view.frame.size.width/2.0, 50);
_bezierPoints = [NSMutableArray arrayWithObjects:
[[BezierPoint alloc] initWithPoint:CGPointMake(startPoint.x, startPoint.y)
angle:M_PI_2 * 0.05
weight:100.0/1.7],
[[BezierPoint alloc] initWithPoint:CGPointMake(startPoint.x + 100.0, startPoint.y + 70.0)
angle:M_PI_2
weight:70.0/1.7],
[[BezierPoint alloc] initWithPoint:CGPointMake(startPoint.x, startPoint.y + 140.0)
angle:M_PI
weight:100.0/1.7],
[[BezierPoint alloc] initWithPoint:CGPointMake(startPoint.x - 100.0, startPoint.y + 70.0)
angle:M_PI_2 * 3.0
weight:70.0/1.7],
[[BezierPoint alloc] initWithPoint:CGPointMake(startPoint.x + 10.0, startPoint.y + 10)
angle:0.0
weight:100.0/1.7],
nil];
}
- (CGPoint)calculateForwardControlPoint:(NSUInteger)index
{
BezierPoint *bezierPoint = _bezierPoints[index];
return CGPointMake(bezierPoint.point.x + cosf(bezierPoint.angle) * bezierPoint.weight,
bezierPoint.point.y + sinf(bezierPoint.angle) * bezierPoint.weight);
}
- (CGPoint)calculateReverseControlPoint:(NSUInteger)index
{
BezierPoint *bezierPoint = _bezierPoints[index];
return CGPointMake(bezierPoint.point.x - cosf(bezierPoint.angle) * bezierPoint.weight,
bezierPoint.point.y - sinf(bezierPoint.angle) * bezierPoint.weight);
}
- (UIBezierPath *)bezierPath
{
UIBezierPath *path = [UIBezierPath bezierPath];
BezierPoint *bezierPoint = _bezierPoints[0];
[path moveToPoint:bezierPoint.point];
for (NSInteger i = 1; i < [_bezierPoints count]; i++)
{
bezierPoint = _bezierPoints[i];
[path addCurveToPoint:bezierPoint.point
controlPoint1:[self calculateForwardControlPoint:i - 1]
controlPoint2:[self calculateReverseControlPoint:i]];
}
return path;
}
當我渲染成UIImage
(使用下面的代碼)這個,我不沒有看到圖像的任何軟化,但可以肯定的是圖像不完全相同。 (我比較capture
所呈現的圖像與通過同時按下我的物理設備上的電源和主頁按鈕以手動方式捕獲的圖像)。
如果您看到一些軟化,我會建議renderInContext
(如下所示)。我想知道你是否把圖像寫成JPG(這是有損的)。也許嘗試PNG,如果你使用JPG。
- (void)drawBezier
{
UIBezierPath *path = [self bezierPath];
CAShapeLayer *oval = [[CAShapeLayer alloc] init];
oval.path = path.CGPath;
oval.strokeColor = [UIColor redColor].CGColor;
oval.fillColor = [UIColor clearColor].CGColor;
oval.lineWidth = 5.0;
oval.strokeStart = 0.0;
oval.strokeEnd = 1.0;
[self.view.layer addSublayer:oval];
}
- (void)capture
{
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.view.layer renderInContext:context];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// save the image
NSData *data = UIImagePNGRepresentation(screenshot);
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *imagePath = [documentsPath stringByAppendingPathComponent:@"image.png"];
[data writeToFile:imagePath atomically:YES];
// send it to myself so I can look at the file
NSURL *url = [NSURL fileURLWithPath:imagePath];
UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:@[url]
applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
}
來源
2012-12-24 13:35:14
Rob
首先感謝您的答案。我一定會嘗試這個。如果你想看看我如何繪製曲線,那麼你可以看到我發佈的這個問題並由我回答。 http://stackoverflow.com/questions/13719143/draw-graph-curves-with-uibezierpath事實上,你已經給出了這個問題的完美答案。然而,我的問題更多的是曲線的尖銳邊緣而不是平滑的曲線。如果我直接在視圖上繪製它們,曲線邊緣會很平滑。使用CATiledLayer繪製整個視圖導致了一些問題,所以我選擇將整個圖形繪製爲圖像。 –
@AbidHussain我的代碼,或者更重要的是,觀察控制點的斜率和結束/起點,解決了我稱之爲「一階導數不連續性」的事實,即曲線急劇轉向一個事實點。如果還有其他問題需要解決,請告訴我。聽起來像你正在描述一些渲染問題,但我沒有完全遵循你的挑戰。我以爲你只是想解決不連續性問題。在渲染方面,我通常只是創建一個'CAShapeLayer'並將其路徑設置爲我的'UIBezierPath'。 – Rob
是的,事實上,我正在面對模糊的曲線渲染,同時在UIGraphicsBeginImageContextWithOptions中繪製了我的繪圖截圖。如果我直接在UIView上繪製它,而不是在UIView上繪製我的繪圖的UIImage,則渲染是正確的。 –