2011-01-25 10 views
1

なぜこれが動作していないのかを解明しようとしている間、私は長い間壁に頭をぶつけていました。CGPathにCGPathをクリッピングする

基本的には、CGPathを使ってグラフ(図)をプロットし、グラデーションをクリップするのに使っています。エンドエフェクトは、iPhoneに付属のStocksアプリのようにする必要があります。

勾配とパスは、2つのレイヤード(クリップされていない)要素として別々に描画されます。しかし、CGContextDrawPathをコメントアウトすると、線もグラデーションも画面に描画されません。これは単なる一連の線分をプロット

CGContextRef context = UIGraphicsGetCurrentContext(); 

[[UIColor whiteColor] set]; 
CGContextSetLineWidth(context, 2.0f); 
CGPoint lastDrawnPt = [[points objectAtIndex:0] CGPointValue]; 
CGPoint firstDrawnPt = lastDrawnPt; 
//create the path for the gradient 
CGMutablePathRef thePath = CGPathCreateMutable(); 
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom left 
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y); 


for (int i=0; i<(points.count-1); i++) { 
    //CGPoint pt1 = [[points objectAtIndex:i] CGPointValue]; 
    CGPoint pt2 = [[points objectAtIndex:i+1] CGPointValue]; 
    if (pt2.x > lastDrawnPt.x+2) { 
     // only draw if we've moved sunstantially to the right 

     //for the gradient 
     CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y); 
     CGPathAddLineToPoint(thePath, NULL, pt2.x, pt2.y); 


     lastDrawnPt = pt2; 
    } 
} 

//finish the gradient clipping path 
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y); 
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom right 
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); 
CGPathAddLineToPoint(thePath, NULL, firstDrawnPt.x, self.bounds.size.height); // bottom right 

CGPathCloseSubpath(thePath); 

//add the gradient clipping path to the context 
CGContextSaveGState(context); 
CGContextAddPath(context, thePath); 

//draw the path 
float components[4] = {1.0, 1.0, 1.0, 1.0}; 
CGContextSetStrokeColor(context, components); 
CGContextDrawPath(context,kCGPathStroke); 

//clip the path 
CGContextClip(context); 


//Draw Gradient 
UIColor *topColor = [UIColor colorWithRed: 1.0 green:1.0 blue:1.0 alpha:1.0]; 
UIColor *bottomColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.0]; 
CGColorRef colorRef[] = { [topColor CGColor], [bottomColor CGColor] }; 
CFArrayRef colors = CFArrayCreate(NULL, (const void**)colorRef, sizeof(colorRef)/sizeof(CGColorRef), &kCFTypeArrayCallBacks); 

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colors, NULL); 
CFRelease(colorSpace); 
CFRelease(colors); 

// Draw a linear gradient from top to bottom 
CGPoint gradStartPoint = CGPointMake(50.0, self.bounds.size.height); 
CGPoint gradEndPoint = CGPointMake(50.0, 0.0); 
CGContextDrawLinearGradient(context, gradient, gradStartPoint, gradEndPoint, 0); 

CFRelease(gradient); 

// Cleanup 
CGColorSpaceRelease(colorSpace); 

CGContextRestoreGState(context); 
+0

CGContextFlushまたはCGContextSynchronizeを試してみましたか...私はそれがレイヤリングと関係していると考えています。また、グラデーションが描画された後にCGContextClipを動かしてみてください。 – namar0x0309

+0

アイデアありがとうございますが、助けてくれないようです。 – avance

+0

私は自分の道を構築する方法に何か問題があると思っています。 – avance

答えて

1
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom left 
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y); 


for (int i=0; i<(points.count-1); i++) { 
    //CGPoint pt1 = [[points objectAtIndex:i] CGPointValue]; 
    CGPoint pt2 = [[points objectAtIndex:i+1] CGPointValue]; 
    if (pt2.x > lastDrawnPt.x+2) { 
     // only draw if we've moved sunstantially to the right 

     //for the gradient 
     CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y); 
     CGPathAddLineToPoint(thePath, NULL, pt2.x, pt2.y); 


     lastDrawnPt = pt2; 
    } 
} 

//finish the gradient clipping path 
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, lastDrawnPt.y); 
CGPathAddLineToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); // bottom right 
CGPathMoveToPoint(thePath, NULL, lastDrawnPt.x, self.bounds.size.height); 
CGPathAddLineToPoint(thePath, NULL, firstDrawnPt.x, self.bounds.size.height); // bottom right 

は、ここに私のdrawRectコードです。特定のポイント値については、次のようになります。

| |||| | 

単一の連続した形状をプロットしません。そのため、このパスは効果的に空であるため、クリッピングには役に立たない。あなたが見たように、それにクリッピングすると、クリッピングパスの中にそれ以上描画されなくなります。

毎年lineto,curveto,arcなどが現在のところから動作します。あなたはそれアップデートそれ、当初movetoとが、それぞれlinetocurvetoarcなどない明確ない現在のポイントという設定しました。したがって、単一の図形を作成するには、lineto(またはcurvetoまたはarc)の連続が続き、最終的にclosepathに続く1つの図形を作成します。

CGPathCloseSubpath(thePath); 

これはパスにのみ閉じた形状を作成し、しかし... closepathと言えば、その形状は、ゼロの領域(自身に戻って倍増のみ線分である)を有しているので、それをクリッピングの目的にはまだ役に立たない。

少なくとも、movetoセグメントのうちの1つ(ループ内のもの、それ以降のものでない場合)を切り捨てる必要があると思われます。次に、インデックスを使用する代わりに、配列のループ使用高速列挙を簡略化し、最後に描画された点を追跡して切り取ることができます。

また、NSArrayへのインデックスのタイプは、であり、intではありません。あなたのタイプを一致させておく - 後で道路を痛めるのを避けます。

+0

あまりにもピーターに感謝します!それはそれだった。私はCGPathがどのように働いていたのかを危険に穏やかに理解していました。 – avance

+0

[NSArray objectAtIndex:i]のNSUIntegerとintについては、メソッドが自動的にintをNSUIntegerにキャストしていませんか? – avance

+0

@ juggleware:いいえ、言語はそうですが、まずは正しいタイプを使用すべきではありません。間違った型を使用すると、十分にカウントアップできないか、あまりにも大きくカウントアップできなくなる可能性があります(負の範囲にオーバーフローした場合の後者は、NSUIntegerのような符号なしの型にキャストすると、巨大な数字になる)。適切なタイプを使用すると、これらの問題を回避できます。 –

関連する問題