i want to draw a shape like in the attached image using core graphics in iOS. Is this possible. Please provide sample code if it possible.
I want at least 3 color gradient over the shape.
i want to draw a shape like in the attached image using core graphics in iOS. Is this possible. Please provide sample code if it possible.
I want at least 3 color gradient over the shape.
Gradients don't naturally draw along path. You have to simulate it. The code is using NSBezierPath, NSView and CGContext but it should not be hard to port it to iOS.
I did with an assembly of trapezoids.
Here is the drawRect of the NSView drawing the gradients:
@implementation grad
-(void)drawRect:(NSRect)dirtyRect {
[[NSColor whiteColor]set];
NSRectFill([self bounds]);
float dim = MIN(self.bounds.size.width, self.bounds.size.height);
int subdiv=512;
float r=dim/4;
float R=dim/2;
float halfinteriorPerim = M_PI*r;
float halfexteriorPerim = M_PI*R;
float smallBase= halfinteriorPerim/subdiv;
float largeBase= halfexteriorPerim/subdiv;
NSBezierPath * cell = [NSBezierPath bezierPath];
[cell moveToPoint:NSMakePoint(- smallBase/2, r)];
[cell lineToPoint:NSMakePoint(+ smallBase/2, r)];
[cell lineToPoint:NSMakePoint( largeBase /2 , R)];
[cell lineToPoint:NSMakePoint(-largeBase /2, R)];
[cell closePath];
float incr = M_PI / subdiv;
CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];
CGContextTranslateCTM(ctx, +self.bounds.size.width/2, +self.bounds.size.height/2);
CGContextScaleCTM(ctx, 0.9, 0.9);
CGContextRotateCTM(ctx, M_PI/2);
CGContextRotateCTM(ctx,-incr/2);
for (int i=0;i<subdiv;i++) {
// replace this color with a color extracted from your gradient object
[[NSColor colorWithCalibratedHue:(float)i/subdiv saturation:1 brightness:1 alpha:1] set];
[cell fill];
[cell stroke];
CGContextRotateCTM(ctx, -incr);
}
}
This looks like this, with various combinations of subdiv
and r
(interior radius), and at different scales.
This version uses Objective-C blocks for color and contour functions. Just pass in a block a function that returns the inner radius, outer radius, and color for any number between 0 and 1. Other parameters are start angle, end angle, number of subdivisions, center, and a scale for debugging purpose, and a CGContextRef.
#import "GradientView.h"
@implementation GradientView
typedef void (^voidBlock)(void);
typedef float (^floatfloatBlock)(float);
typedef UIColor * (^floatColorBlock)(float);
-(CGPoint) pointForTrapezoidWithAngle:(float)a andRadius:(float)r forCenter:(CGPoint)p{
return CGPointMake(p.x + r*cos(a), p.y + r*sin(a));
}
-(void)drawGradientInContext:(CGContextRef)ctx startingAngle:(float)a endingAngle:(float)b intRadius:(floatfloatBlock)intRadiusBlock outRadius:(floatfloatBlock)outRadiusBlock withGradientBlock:(floatColorBlock)colorBlock withSubdiv:(int)subdivCount withCenter:(CGPoint)center withScale:(float)scale
{
float angleDelta = (b-a)/subdivCount;
float fractionDelta = 1.0/subdivCount;
CGPoint p0,p1,p2,p3, p4,p5;
float currentAngle=a;
p4=p0 = [self pointForTrapezoidWithAngle:currentAngle andRadius:intRadiusBlock(0) forCenter:center];
p5=p3 = [self pointForTrapezoidWithAngle:currentAngle andRadius:outRadiusBlock(0) forCenter:center];
CGMutablePathRef innerEnveloppe=CGPathCreateMutable(),
outerEnveloppe=CGPathCreateMutable();
CGPathMoveToPoint(outerEnveloppe, 0, p3.x, p3.y);
CGPathMoveToPoint(innerEnveloppe, 0, p0.x, p0.y);
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx, 1);
for (int i=0;i<subdivCount;i++)
{
float fraction = (float)i/subdivCount;
currentAngle=a+fraction*(b-a);
CGMutablePathRef trapezoid = CGPathCreateMutable();
p1 = [self pointForTrapezoidWithAngle:currentAngle+angleDelta andRadius:intRadiusBlock(fraction+fractionDelta) forCenter:center];
p2 = [self pointForTrapezoidWithAngle:currentAngle+angleDelta andRadius:outRadiusBlock(fraction+fractionDelta) forCenter:center];
CGPathMoveToPoint(trapezoid, 0, p0.x, p0.y);
CGPathAddLineToPoint(trapezoid, 0, p1.x, p1.y);
CGPathAddLineToPoint(trapezoid, 0, p2.x, p2.y);
CGPathAddLineToPoint(trapezoid, 0, p3.x, p3.y);
CGPathCloseSubpath(trapezoid);
CGPoint centerofTrapezoid = CGPointMake((p0.x+p1.x+p2.x+p3.x)/4, (p0.y+p1.y+p2.y+p3.y)/4);
CGAffineTransform t = CGAffineTransformMakeTranslation(-centerofTrapezoid.x, -centerofTrapezoid.y);
CGAffineTransform s = CGAffineTransformMakeScale(scale, scale);
CGAffineTransform concat = CGAffineTransformConcat(t, CGAffineTransformConcat(s, CGAffineTransformInvert(t)));
CGPathRef scaledPath = CGPathCreateCopyByTransformingPath(trapezoid, &concat);
CGContextAddPath(ctx, scaledPath);
CGContextSetFillColorWithColor(ctx,colorBlock(fraction).CGColor);
CGContextSetStrokeColorWithColor(ctx, colorBlock(fraction).CGColor);
CGContextSetMiterLimit(ctx, 0);
CGContextDrawPath(ctx, kCGPathFillStroke);
CGPathRelease(trapezoid);
p0=p1;
p3=p2;
CGPathAddLineToPoint(outerEnveloppe, 0, p3.x, p3.y);
CGPathAddLineToPoint(innerEnveloppe, 0, p0.x, p0.y);
}
CGContextSetLineWidth(ctx, 10);
CGContextSetLineJoin(ctx, kCGLineJoinRound);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextAddPath(ctx, outerEnveloppe);
CGContextAddPath(ctx, innerEnveloppe);
CGContextMoveToPoint(ctx, p0.x, p0.y);
CGContextAddLineToPoint(ctx, p3.x, p3.y);
CGContextMoveToPoint(ctx, p4.x, p4.y);
CGContextAddLineToPoint(ctx, p5.x, p5.y);
CGContextStrokePath(ctx);
}
-(void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor whiteColor] set];
UIRectFill(self.bounds);
CGRect r = self.bounds;
r=CGRectInset(r, 60, 60);
if (r.size.width > r.size.height)
r.size.width=r.size.height;
else r.size.height=r.size.width;
float radius=r.size.width/2;
[self drawGradientInContext:ctx startingAngle:M_PI/16 endingAngle:2*M_PI-M_PI/16 intRadius:^float(float f) {
// return 0*f + radius/2*(1-f);
return 200+10*sin(M_PI*2*f*7);
// return 50+sqrtf(f)*200;
// return radius/2;
} outRadius:^float(float f) {
// return radius *f + radius/2*(1-f);
return radius;
// return 300+10*sin(M_PI*2*f*17);
} withGradientBlock:^UIColor *(float f) {
// return [UIColor colorWithHue:f saturation:1 brightness:1 alpha:1];
float sr=90, sg=54, sb=255;
float er=218, eg=0, eb=255;
return [UIColor colorWithRed:(f*sr+(1-f)*er)/255. green:(f*sg+(1-f)*eg)/255. blue:(f*sb+(1-f)*eb)/255. alpha:1];
} withSubdiv:256 withCenter:CGPointMake(CGRectGetMidX(r), CGRectGetMidY(r)) withScale:1];
}
@end
Examples:
CGContext
:Use +[UIBezierPath bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:]
to create a path containing a semi-circular arc. Then use CGPathCreateCopyByStrokingPath
to create an enclosed shape around the arc. Use CGContextAddPath
to add this enclosed shape to your context's path, then use CGContextClip
to set the clip region to the thick arc.
Use CGGradientCreateWithColors
to create a CGGradient
with your rainbow colors. Use CGContextDrawLinearGradient
to fill the clip region with the gradient.
CALayer
:Create a CAGradientLayer
. Set the layer's colors
property to your rainbow of colors. Set the layer's startPoint
to (0,0) and the layer's endPoint
to (1,0).
Create a CAShapeLayer
and set it as the gradient layer's mask. Use +[UIBezierPath bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:]
and CGPathCreateCopyByStrokingPath
to create a path enclosing the thick arc, and set this path as the shape layer's path
.
Since iOS 8, the simplest and fastest way to draw circular gradients is using Core Image filters. A kernel is linked to in the comments to this answer, but since figuring out how to actually use it took me a while, I'll post the entire process here.
Essentially, Core Image filters are little fragment shaders that run on every pixel of an input image. Although they were designed to filter images, you can use them to generate images by simply ignoring the input pixel value in your filter kernel.
The code below generates a dummy image to use as the input, then applies a custom CI kernel to it to make a circular gradient.
// 1 - generate a dummy image of the required size
UIGraphicsBeginImageContextWithOptions(CGSizeMake(512.0, 256.0), NO, [[UIScreen mainScreen] scale]);
CIImage *dummyImage = [CIImage imageWithCGImage:UIGraphicsGetImageFromCurrentImageContext().CGImage];
// 2 - define the kernel algorithm
NSString *kernelString = @"kernel vec4 circularGradientKernel(__color startColor, __color endColor, vec2 center, float innerR, float outerR) { \n"
" vec2 point = destCoord() - center;"
" float rsq = point.x * point.x + point.y * point.y;"
" float theta = mod(atan(point.y, point.x), radians(360.0));"
" return (rsq > innerR*innerR && rsq < outerR*outerR) ? mix(startColor, endColor, theta/radians(360.0)*2.0) : vec4(0.0, 0.0, 0.0, 1.0);"
"}";
// 3 - initialize a Core Image context and the filter kernel
CIContext *context = [CIContext contextWithOptions:nil];
CIColorKernel *kernel = [CIColorKernel kernelWithString:kernelString];
// 4 - argument array, corresponding to the first line of the kernel string
NSArray *args = @[ [CIColor colorWithRed:1.0 green:0.0 blue:0.0],
[CIColor colorWithRed:0.0 green:0.0 blue:1.0],
[CIVector vectorWithCGPoint:CGPointMake(CGRectGetMidX(dummyImage.extent),CGRectGetMinY(dummyImage.extent))],
[NSNumber numberWithFloat:250.0],
[NSNumber numberWithFloat:500.0]];
// 5 - apply the kernel to our dummy image, and convert the result to a UIImage
CIImage *ciOutputImage = [kernel applyWithExtent:dummyImage.extent arguments:args];
CGImageRef cgOutput = [context createCGImage:ciOutputImage fromRect:ciOutputImage.extent];
UIImage *gradientImage = [UIImage imageWithCGImage:cgOutput];
CGImageRelease(cgOutput);
The output looks like this:
The colors and the center point are passed in packaged as CIColor
s and CIVector
s, and the radii of the inner and outer circles are given as floats. You can of course modify the argument list if you want to pass in other parameters.
This method is even fast enough to use for animation, although if you want to do this make sure you use the same context for each frame, as creating and tearing it down is a performance bottleneck. Just make sure your animation parameter is an input argument and loop over steps 4 and 5.
Also, don't forget the call to CGImageRelease
at the end, or you'll have a memory leak.
I used Antoine's answer and adjusted it for iOS:
-(void)drawRect:(CGRect)rect {
// http://stackoverflow.com/a/12775798/129202
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor whiteColor] set]; //[[NSColor whiteColor]set];
UIRectFill([self bounds]);
float dim = MIN(self.bounds.size.width, self.bounds.size.height);
int subdiv=512;
float r=dim/4;
float R=dim/2;
float halfinteriorPerim = M_PI*r;
float halfexteriorPerim = M_PI*R;
float smallBase= halfinteriorPerim/subdiv;
float largeBase= halfexteriorPerim/subdiv;
UIBezierPath * cell = [UIBezierPath bezierPath];
[cell moveToPoint:CGPointMake(- smallBase/2, r)];
[cell addLineToPoint:CGPointMake(+ smallBase/2, r)];
[cell addLineToPoint:CGPointMake( largeBase /2 , R)];
[cell addLineToPoint:CGPointMake(-largeBase /2, R)];
[cell closePath];
float incr = M_PI / subdiv;
//CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];
CGContextTranslateCTM(context, +self.bounds.size.width/2, +self.bounds.size.height/2);
CGContextScaleCTM(context, 0.9, 0.9);
CGContextRotateCTM(context, M_PI/2);
CGContextRotateCTM(context,-incr/2);
for (int i=0;i<subdiv;i++) {
// replace this color with a color extracted from your gradient object
[[UIColor colorWithHue:(float)i/subdiv saturation:1 brightness:1 alpha:1] set];
[cell fill];
[cell stroke];
CGContextRotateCTM(context, -incr);
}
}
As another answer, I found this: https://github.com/paiv/AngleGradientLayer
I tried it out and it works well. I haven't looked into the implementation. I don't think I need to. :-)
Code at this point:
//
// The MIT License (MIT)
//
// Copyright (C) 2012 Pavel Ivashkov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// AngleGradientLayer.m
// paiv
//
// Created by Pavel Ivashkov on 2012-02-12.
//
#import "AngleGradientLayer.h"
#if __has_feature(objc_arc)
#define BRIDGE_CAST(T) (__bridge T)
#else
#define BRIDGE_CAST(T) (T)
#endif
#define byte unsigned char
#define F2CC(x) ((byte)(255 * x))
#define RGBAF(r,g,b,a) (F2CC(r) << 24 | F2CC(g) << 16 | F2CC(b) << 8 | F2CC(a))
#define RGBA(r,g,b,a) ((byte)r << 24 | (byte)g << 16 | (byte)b << 8 | (byte)a)
#define RGBA_R(c) ((uint)c >> 24 & 255)
#define RGBA_G(c) ((uint)c >> 16 & 255)
#define RGBA_B(c) ((uint)c >> 8 & 255)
#define RGBA_A(c) ((uint)c >> 0 & 255)
@interface AngleGradientLayer()
- (CGImageRef)newImageGradientInRect:(CGRect)rect;
@end
static void angleGradient(byte* data, int w, int h, int* colors, int colorCount, float* locations, int locationCount);
@implementation AngleGradientLayer
- (id)init
{
if (!(self = [super init]))
return nil;
self.needsDisplayOnBoundsChange = YES;
return self;
}
#if !__has_feature(objc_arc)
- (void)dealloc
{
[_colors release];
[_locations release];
[super dealloc];
}
#endif
- (void)drawInContext:(CGContextRef)ctx
{
CGContextSetFillColorWithColor(ctx, self.backgroundColor);
CGRect rect = CGContextGetClipBoundingBox(ctx);
CGContextFillRect(ctx, rect);
CGImageRef img = [self newImageGradientInRect:rect];
CGContextDrawImage(ctx, rect, img);
CGImageRelease(img);
}
- (CGImageRef)newImageGradientInRect:(CGRect)rect
{
return [[self class] newImageGradientInRect:rect colors:self.colors locations:self.locations];
}
+ (CGImageRef)newImageGradientInRect:(CGRect)rect colors:(NSArray *)colors locations:(NSArray *)locations
{
int w = CGRectGetWidth(rect);
int h = CGRectGetHeight(rect);
int bitsPerComponent = 8;
int bpp = 4 * bitsPerComponent / 8;
int byteCount = w * h * bpp;
int colorCount = (int)colors.count;
int locationCount = (int)locations.count;
int* cols = NULL;
float* locs = NULL;
if (colorCount > 0) {
cols = calloc(colorCount, bpp);
int *p = cols;
for (id cg in colors) {
CGColorRef c = BRIDGE_CAST(CGColorRef)cg;
float r, g, b, a;
size_t n = CGColorGetNumberOfComponents(c);
const CGFloat *comps = CGColorGetComponents(c);
if (comps == NULL) {
*p++ = 0;
continue;
}
r = comps[0];
if (n >= 4) {
g = comps[1];
b = comps[2];
a = comps[3];
}
else {
g = b = r;
a = comps[1];
}
*p++ = RGBAF(r, g, b, a);
}
}
if (locationCount > 0 && locationCount == colorCount) {
locs = calloc(locationCount, sizeof(locs[0]));
float *p = locs;
for (NSNumber *n in locations) {
*p++ = [n floatValue];
}
}
byte* data = malloc(byteCount);
angleGradient(data, w, h, cols, colorCount, locs, locationCount);
if (cols) free(cols);
if (locs) free(locs);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Little;
CGContextRef ctx = CGBitmapContextCreate(data, w, h, bitsPerComponent, w * bpp, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
CGImageRef img = CGBitmapContextCreateImage(ctx);
CGContextRelease(ctx);
free(data);
return img;
}
@end
static inline byte blerp(byte a, byte b, float w)
{
return a + w * (b - a);
}
static inline int lerp(int a, int b, float w)
{
return RGBA(blerp(RGBA_R(a), RGBA_R(b), w),
blerp(RGBA_G(a), RGBA_G(b), w),
blerp(RGBA_B(a), RGBA_B(b), w),
blerp(RGBA_A(a), RGBA_A(b), w));
}
static inline int multiplyByAlpha(int c)
{
float a = RGBA_A(c) / 255.0;
return RGBA((byte)(RGBA_R(c) * a),
(byte)(RGBA_G(c) * a),
(byte)(RGBA_B(c) * a),
RGBA_A(c));
}
void angleGradient(byte* data, int w, int h, int* colors, int colorCount, float* locations, int locationCount)
{
if (colorCount < 1) return;
if (locationCount > 0 && locationCount != colorCount) return;
int* p = (int*)data;
float centerX = (float)w / 2;
float centerY = (float)h / 2;
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
float dirX = x - centerX;
float dirY = y - centerY;
float angle = atan2f(dirY, dirX);
if (dirY < 0) angle += 2 * M_PI;
angle /= 2 * M_PI;
int index = 0, nextIndex = 0;
float t = 0;
if (locationCount > 0) {
for (index = locationCount - 1; index >= 0; index--) {
if (angle >= locations[index]) {
break;
}
}
if (index >= locationCount) index = locationCount - 1;
nextIndex = index + 1;
if (nextIndex >= locationCount) nextIndex = locationCount - 1;
float ld = locations[nextIndex] - locations[index];
t = ld <= 0 ? 0 : (angle - locations[index]) / ld;
}
else {
t = angle * (colorCount - 1);
index = t;
t -= index;
nextIndex = index + 1;
if (nextIndex >= colorCount) nextIndex = colorCount - 1;
}
int lc = colors[index];
int rc = colors[nextIndex];
int color = lerp(lc, rc, t);
color = multiplyByAlpha(color);
*p++ = color;
}
}
I spent a long time searching for how to do this, too, so I thought I'd post the way I ended up doing it. It turns out both answers are in excellent answer to this question:
Draw segments from a circle or donut
For my purposes, I only used the drawing and gradient parts of that answer. The structure looks more or less like this...
CGContextRef context = UIGraphicsGetCurrentcontext();
CGFloat arcStartAngle = M_PI;
CGFloat arcEndAngle = 2 * M_PI;
CGPoint startPoint = CGPointMake(...);
CGPoint endPoint = CGPointMake(...);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat colors[] =
{
1.0, 0.0, 0.0, 1.0, //RGBA values (so red to green in this case)
0.0, 1.0, 0.0, 1.0
};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
//Where the 2 is for the number of color components. You can have more colors throughout //your gradient by adding to the colors[] array, and changing the components value.
CGColorSpaceRelease(colorSpace);
//Now for the arc part...
CGMutablePathRef arc = CGPathCreateMutable();
CGPathMoveToPoint(arc, NULL, startPoint.x, startPoint.y);
//Here, the CGPoint self.arcCenter is the point around which the arc is placed, so maybe the
//middle of your view. self.radius is the distance between this center point and the arc.
CGPathAddArc(arc, NULL, self.arcCenter.x, self.arcCenter.y, self.radius,
arcStartAngle, arcEndAngle, YES);
//This essentially draws along the path in an arc shape
CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(arc, NULL, 5.0f,
kCGLineCapButt, kCGLineJoinMiter, 10);
CGContextSaveGState(context);
CGContextAddPath(context, strokedArc);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextDrawPath(context, kCGPathFillStroke);
CGGradientRelease(gradient);
CGContextRestoreGState(context);
//This all draws a gradient that is much larger than the arc itself, but using
//CGContextClip, it clips out everything EXCEPT the colors in the arc. Saving and Restoring
//the state allows you to preserve any other drawing going on. If you didn't use these,
//then all other drawing would also be clipped.
I hope this helps. If any of this is unclear, I recommend you check out the question link above. The answer to that questions contains everything I used in this answer and a few more cool and useful drawing tips.
I've used alecail's answer(iOS with blocks), however, I noticed that it needed a few adjustments (just added a few CGPathRelease() to the -(void) drawGratientInContext:... ) because it was using too much memory. Sorry, I'd post this as a comment, but as I don't have 50+ reputation, I'll have to answer as the following:
-(void)drawGradientInContext:(CGContextRef)ctx startingAngle:(float)a endingAngle:(float)b intRadius:(floatfloatBlock)intRadiusBlock outRadius:(floatfloatBlock)outRadiusBlock withGradientBlock:(floatColorBlock)colorBlock withSubdiv:(int)subdivCount withCenter:(CGPoint)center withScale:(float)scale
{
float angleDelta = (b-a)/subdivCount;
float fractionDelta = 1.0/subdivCount;
CGPoint p0,p1,p2,p3, p4,p5;
float currentAngle=a;
p4=p0 = [self pointForTrapezoidWithAngle:currentAngle andRadius:intRadiusBlock(0) forCenter:center];
p5=p3 = [self pointForTrapezoidWithAngle:currentAngle andRadius:outRadiusBlock(0) forCenter:center];
CGMutablePathRef innerEnveloppe=CGPathCreateMutable(),
outerEnveloppe=CGPathCreateMutable();
CGPathMoveToPoint(outerEnveloppe, 0, p3.x, p3.y);
CGPathMoveToPoint(innerEnveloppe, 0, p0.x, p0.y);
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx, 1);
for (int i=0;i<subdivCount;i++)
{
float fraction = (float)i/subdivCount;
currentAngle=a+fraction*(b-a);
CGMutablePathRef trapezoid = CGPathCreateMutable();
p1 = [self pointForTrapezoidWithAngle:currentAngle+angleDelta andRadius:intRadiusBlock(fraction+fractionDelta) forCenter:center];
p2 = [self pointForTrapezoidWithAngle:currentAngle+angleDelta andRadius:outRadiusBlock(fraction+fractionDelta) forCenter:center];
CGPathMoveToPoint(trapezoid, 0, p0.x, p0.y);
CGPathAddLineToPoint(trapezoid, 0, p1.x, p1.y);
CGPathAddLineToPoint(trapezoid, 0, p2.x, p2.y);
CGPathAddLineToPoint(trapezoid, 0, p3.x, p3.y);
CGPathCloseSubpath(trapezoid);
CGPoint centerofTrapezoid = CGPointMake((p0.x+p1.x+p2.x+p3.x)/4, (p0.y+p1.y+p2.y+p3.y)/4);
CGAffineTransform t = CGAffineTransformMakeTranslation(-centerofTrapezoid.x, -centerofTrapezoid.y);
CGAffineTransform s = CGAffineTransformMakeScale(scale, scale);
CGAffineTransform concat = CGAffineTransformConcat(t, CGAffineTransformConcat(s, CGAffineTransformInvert(t)));
CGPathRef scaledPath = CGPathCreateCopyByTransformingPath(trapezoid, &concat);
CGContextAddPath(ctx, scaledPath);
CGContextSetFillColorWithColor(ctx,colorBlock(fraction).CGColor);
CGContextSetStrokeColorWithColor(ctx, colorBlock(fraction).CGColor);
CGContextSetMiterLimit(ctx, 0);
CGContextDrawPath(ctx, kCGPathFillStroke);
p0=p1;
p3=p2;
CGPathAddLineToPoint(outerEnveloppe, 0, p3.x, p3.y);
CGPathAddLineToPoint(innerEnveloppe, 0, p0.x, p0.y);
//Release both CGPathRefs. The original code just released
//trapezoid CG .
CGPathRelease(trapezoid);
CGPathRelease(scaledPath);
}
//stroke width
CGContextSetLineWidth(ctx, 0.0001);
CGContextSetLineJoin(ctx, kCGLineJoinRound);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextAddPath(ctx, outerEnveloppe);
CGContextAddPath(ctx, innerEnveloppe);
CGContextMoveToPoint(ctx, p0.x, p0.y);
CGContextAddLineToPoint(ctx, p3.x, p3.y);
CGContextMoveToPoint(ctx, p4.x, p4.y);
CGContextAddLineToPoint(ctx, p5.x, p5.y);
CGContextStrokePath(ctx);
//Release CGPathRefs
CGPathRelease(innerEnveloppe);
CGPathRelease(outerEnveloppe);
}