1

UIBezierPathメソッドとコアテキストを使用してグラフビューを描画しています。方法を使っ addQuadCurveToPoint:controlPoint:てグラフに曲線を描きます。CATiledLayerまた、x軸に大きなデータセットを持つグラフをレンダリングする目的で使用します。グラフ全体を画像コンテキストでdrawrect:描画し、ビューの方法でこの画像をビュー全体で描画します。以下は私のコードです。

- (void)drawImage{

        UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);

        // Draw Curves 
        [self drawDiagonal];

        UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
        [screenshot retain];
        UIGraphicsEndImageContext();
}
- (void)drawRect:(CGRect)rect{

    NSLog(@"Draw iN rect with Bounds: %@",NSStringFromCGRect(rect));
    [screenshot drawInRect:self.frame];
}

ただし、スクリーンショットでは、2点間に描かれた曲線は滑らかではありません。また、情報リストで[アンチエイリアスを使用したレンダリング]を[はい]に設定しました。スクリーンショットをご覧ください。 ここに画像の説明を入力してください

4

1 に答える 1

1

をどのように作成するかを確認する必要がありますUIBezierPathが、私の経験では、滑らかな曲線の場合、重要な問題は、曲線の制御点と曲線の特定のセグメントの終点との間の線の傾きが曲線の始点の次のセグメントとその制御点の間の勾配。addCurveToPointではなくを使用して一般的な滑らかな曲線を描く方が簡単であることがわかりましたaddQuadCurveToPoint。これにより、開始と終了の制御点を調整して、この基準をより一般的に満たすことができます。

この点を説明するために、私が通常UIBezierPath曲線を描く方法は、曲線上に点の配列を持ち、その点で曲線がとるべき角度、そしてaddCurveToPoint制御点の「重み」(つまり、コントロールポイントは)である必要があります。したがって、これらのパラメーターを使用して、aの2番目のコントロールポイントと、UIBezierPathの次のセグメントの最初のcontrolPointを指定し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(不可逆)で書いているのではないでしょうか。JPGを使用している場合は、PNGを試してみてください。

- (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-24T13:35:14.927 に答える