Drawing a bezier curve between a set of given points - ios

What is the best way to draw a bezier curve, in iOS application, that passes through a set of given points

A little more generic way to do it can be achieved by, for example, looking at the BEMSimpleLineGraph GitHub Project (see here for more info: bemsimplelinegraph). Here I extracted a method to draw a bezier curve through a given list of points.
The header file (BezierLine.h):
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>
#interface BezierLine : NSObject
/*
Draws a bezier curved line on the given context
with points: Array of CGPoint values
*/
-(void) drawBezierCurveInContext:(CGContextRef)context withPoints:(NSArray*)points lineColor:(UIColor*)color lineWidth:(CGFloat)lineWidth;
#end
The implementation (BezierLine.m):
#import "BezierLine.h"
#implementation BezierLine
-(void) drawBezierCurveInContext:(CGContextRef)context withPoints:(NSArray*)points lineColor:(UIColor*)color lineWidth:(CGFloat)lineWidth {
if (points.count < 2) return;
CGPoint CP1;
CGPoint CP2;
// LINE
UIBezierPath *line = [UIBezierPath bezierPath];
CGPoint p0;
CGPoint p1;
CGPoint p2;
CGPoint p3;
CGFloat tensionBezier1 = 0.3;
CGFloat tensionBezier2 = 0.3;
CGPoint previousPoint1;
CGPoint previousPoint2;
[line moveToPoint:[[points objectAtIndex:0] CGPointValue]];
for (int i = 0; i < points.count - 1; i++) {
p1 = [[points objectAtIndex:i] CGPointValue];
p2 = [[points objectAtIndex:i + 1] CGPointValue];
const CGFloat maxTension = 1.0f / 3.0f;
tensionBezier1 = maxTension;
tensionBezier2 = maxTension;
if (i > 0) { // Exception for first line because there is no previous point
p0 = previousPoint1;
if (p2.y - p1.y == p1.y - p0.y) tensionBezier1 = 0;
} else {
tensionBezier1 = 0;
p0 = p1;
}
if (i < points.count - 2) { // Exception for last line because there is no next point
p3 = [[points objectAtIndex:i + 2] CGPointValue];
if (p3.y - p2.y == p2.y - p1.y) tensionBezier2 = 0;
} else {
p3 = p2;
tensionBezier2 = 0;
}
// The tension should never exceed 0.3
if (tensionBezier1 > maxTension) tensionBezier1 = maxTension;
if (tensionBezier2 > maxTension) tensionBezier2 = maxTension;
// First control point
CP1 = CGPointMake(p1.x + (p2.x - p1.x)/3,
p1.y - (p1.y - p2.y)/3 - (p0.y - p1.y)*tensionBezier1);
// Second control point
CP2 = CGPointMake(p1.x + 2*(p2.x - p1.x)/3,
(p1.y - 2*(p1.y - p2.y)/3) + (p2.y - p3.y)*tensionBezier2);
[line addCurveToPoint:p2 controlPoint1:CP1 controlPoint2:CP2];
previousPoint1 = p1;
previousPoint2 = p2;
}
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, lineWidth);
CGContextAddPath(context, line.CGPath);
CGContextDrawPath(context, kCGPathStroke);
}
#end
You can use it by for example creating an image context using UIGraphicsBeginImageContext and retrieving the context with UIGraphicsGetCurrentContext().
Otherwise you may want to change the code and assign the resulting Path to a CALayer and add that to an UIView.
Hope this helps.

I know this might be late, but just for anyone who is looking for the right answer. Instead of using addLineToPoint to draw the straight line. You can use addCurveToPoint to draw the curve. e.g.
[bezierPath moveToPoint:CGPointMake(0, 0)];
[bezierPath addCurveToPoint:CGPointMake(40, 100)
controlPoint1:CGPointMake(20, 0)
controlPoint2:CGPointMake(20, 100)];
[bezierPath addCurveToPoint:CGPointMake(80, 50)
controlPoint1:CGPointMake(60, 100)
controlPoint2:CGPointMake(60, 50)];
// and you may don't want to close the path
// [bezierPath closePath];
It's really up to you to choose the control points of the curve. I just use the x = last_point_x + 20; y = last_point_y for control point one, and x = current_point_x - 20; y = current_point_y;
and you may want to use other value instead of the 20 as you may have different segment width of the curve.

You can easily google some example of how to create bezier curve on the web. I found this short tut as an example.
You can create a close bezier curve for e.g. with the following code snippet:
UIBezierPath* path = [UIBezierPath bezierPath];
[path moveToPoint:pt1];
[path addLineToPoint:pt2];
[path addLineToPoint:pt3];
[path closePath];
I hope it will help as a starting point.

Please try this.
UIImageView *waterLevel = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,200,200)];
UIGraphicsBeginImageContext(waterLevel.frame.size);
[waterLevel.image drawAtPoint:CGPointZero];
//define BezierPath
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
[bezierPath moveToPoint:CGPointMake(0, 0)];
[bezierPath addLineToPoint:CGPointMake(waterLevel.frame.size.width, 0)];
[bezierPath addLineToPoint:CGPointMake(waterLevel.frame.size.width, waterLevel.frame.size.height)];
[bezierPath addLineToPoint:CGPointMake(0, waterLevel.frame.size.height)];
[bezierPath closePath];
bezierPath.lineWidth = 15;
//set the stoke color
[[UIColor blackColor] setStroke];
//draw the path
[bezierPath stroke];
// Add to the current Graphic context
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context,bezierPath.CGPath);
waterLevel.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.view addSubview:waterLevel];

You can be much more efficient by using the CGPointFromString method:
NSArray *pointArray = #[#"{3.0,2.5}",#"{100.0,30.2}", #"{100.0,200.0}", #"{3.0,200.0}"];
// draw the path
UIBezierPath *aPath = [UIBezierPath bezierPath];
for (NSString *pointString in pointArray) {
if ([pointArray indexOfObject:pointString] == 0)
[aPath moveToPoint:CGPointFromString(pointString)];
else
[aPath addLineToPoint:CGPointFromString(pointString)];
}
[aPath closePath];

UIBezierPath *aPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(100.0, 0.0)];
// Draw the lines.
[aPath addLineToPoint:CGPointMake(200.0, 40.0)];
[aPath addLineToPoint:CGPointMake(160, 140)];
[aPath addLineToPoint:CGPointMake(40.0, 140)];
[aPath addLineToPoint:CGPointMake(0.0, 40.0)];
[aPath closePath];

Related

Draw VU meter using Core Graphics in iOS

I'm trying to draw a somewhat similar image to this, using Core Graphics:
I was able to draw the main arc, but I am not able to understand, how to divide arc into parts/draw graduation on arc? My current code to draw the arc is:
[path addArcWithCenter:point radius:radius startAngle:DEGREES_TO_RADIANS(specific_start_angle) endAngle:DEGREES_TO_RADIANS(specific_end_angle) clockwise:NO];
I tried using strokeWithBlendMode but I am facing problem with position of graduations or ticks.
Teja's solution will work fine for you, but it does require that you calculate your own start and end points for the graduations.
I suggest you create a function that let's you draw the graduations at a given angle of the arc, that will calculate the start and end points of the graduations, given a length.
static inline void drawGraduation(CGPoint center, CGFloat radius, CGFloat angle, CGFloat length, CGFloat width, CGColorRef color) {
CGContextRef c = UIGraphicsGetCurrentContext();
CGFloat radius2 = radius+length; // The radius of the end points of the graduations
CGPoint p1 = (CGPoint){cos(angle)*radius+center.x, sin(angle)*radius+center.y}; // the start point of the graduation
CGPoint p2 = (CGPoint){cos(angle)*radius2+center.x, sin(angle)*radius2+center.y}; // the end point of the graduation
CGContextMoveToPoint(c, p1.x, p1.y);
CGContextAddLineToPoint(c, p2.x, p2.y);
CGContextSetStrokeColorWithColor(c, color);
CGContextSetLineWidth(c, width);
CGContextStrokePath(c);
}
You can then call this in a for loop (or however you want to do it) when you draw your arc for the main scale of your VU meter. You can also easily customise the color, width and length of given graduations at given intervals (for example, this code gives a thicker & longer red line every 5 graduations).
- (void)drawRect:(CGRect)rect {
CGRect r = self.bounds;
CGFloat startAngle = -M_PI*0.2; // start angle of the main arc
CGFloat endAngle = -M_PI*0.8; // end angle of the main arc
NSUInteger numberOfGraduations = 16;
CGPoint center = (CGPoint){r.size.width*0.5, r.size.height*0.5}; // center of arc
CGFloat radius = (r.size.width*0.5)-20; // radius of arc
CGFloat maxGraduationWidth = 1.5; // the maximum graduation width
CGFloat maxGraduationWidthAngle = maxGraduationWidth/radius; // the maximum graduation width angle (used to prevent the graduations from being stroked outside of the main arc)
// draw graduations
CGFloat deltaArc = (endAngle-startAngle+maxGraduationWidthAngle)/(numberOfGraduations-1); // the change in angle of the arc
CGFloat startArc = startAngle-(maxGraduationWidthAngle*0.5); // the starting angle of the arc
for (int i = 0; i < numberOfGraduations; i++) {
if (i % 5 == 0) {
drawGraduation(center, radius, startArc+(i*deltaArc), 14, 1.5, [UIColor redColor].CGColor); // red graduation every 5 graduations.
} else {
drawGraduation(center, radius, startArc+(i*deltaArc), 10, 1, [UIColor blackColor].CGColor);
}
}
// draw main arc
UIBezierPath* mainArc = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:NO];
[[UIColor blackColor] setStroke];
mainArc.lineWidth = 2;
[mainArc stroke];
}
Output
Full project: https://github.com/hamishknight/VU-Meter-Arc
You can draw bezier path with dashes ,something like this::
//// Bezier Drawing
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(54.5, 62.5)];
[bezierPath addCurveToPoint: CGPointMake(121.5, 39.5) controlPoint1: CGPointMake(54.5, 62.5) controlPoint2: CGPointMake(87.5, 39.5)];
[bezierPath addCurveToPoint: CGPointMake(190.5, 62.5) controlPoint1: CGPointMake(155.5, 39.5) controlPoint2: CGPointMake(190.5, 62.5)];
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 10;
CGFloat bezierPattern[] = {24, 2};
[bezierPath setLineDash: bezierPattern count: 2 phase: 0];
[bezierPath stroke];
Else You can draw multiple bezier path and draw it similar to what you want:
Something like this:
For the small line:
UIBezierPath* bezier2Path = [UIBezierPath bezierPath];
[bezier2Path moveToPoint: CGPointMake(65, 45)];
[bezier2Path addLineToPoint: CGPointMake(75, 63)];
[UIColor.blackColor setStroke];
bezier2Path.lineWidth = 1.5;
[bezier2Path stroke];

Draw Triangle iOS

The code below is drawing me a circle, how can I modify the existing code to draw a triangle instead?
_colorDotLayer = [CALayer layer];
CGFloat width = self.bounds.size.width-6;
_colorDotLayer.bounds = CGRectMake(0, 0, width, width);
_colorDotLayer.allowsGroupOpacity = YES;
_colorDotLayer.backgroundColor = self.annotationColor.CGColor;
_colorDotLayer.cornerRadius = width/2;
_colorDotLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
While there are shown several Core Graphics solution, I want to add a Core Animation based solution.
- (void)viewDidLoad
{
[super viewDidLoad];
UIBezierPath* trianglePath = [UIBezierPath bezierPath];
[trianglePath moveToPoint:CGPointMake(0, view3.frame.size.height-100)];
[trianglePath addLineToPoint:CGPointMake(view3.frame.size.width/2,100)];
[trianglePath addLineToPoint:CGPointMake(view3.frame.size.width, view2.frame.size.height)];
[trianglePath closePath];
CAShapeLayer *triangleMaskLayer = [CAShapeLayer layer];
[triangleMaskLayer setPath:trianglePath.CGPath];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0, size.width, size.height)];
view.backgroundColor = [UIColor colorWithWhite:.75 alpha:1];
view.layer.mask = triangleMaskLayer;
[self.view addSubview:view];
}
code based on my blog post.
#implementation TriangleView {
CAShapeLayer *_colorDotLayer;
}
- (void)layoutSubviews {
[super layoutSubviews];
if (_colorDotLayer == nil) {
_colorDotLayer = [CAShapeLayer layer];
_colorDotLayer.fillColor = self.annotationColor.CGColor;
[self.layer addSublayer:_colorDotLayer];
}
CGRect bounds = self.bounds;
CGFloat radius = (bounds.size.width - 6) / 2;
CGFloat a = radius * sqrt((CGFloat)3.0) / 2;
CGFloat b = radius / 2;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, -radius)];
[path addLineToPoint:CGPointMake(a, b)];
[path addLineToPoint:CGPointMake(-a, b)];
[path closePath];
[path applyTransform:CGAffineTransformMakeTranslation(CGRectGetMidX(bounds), CGRectGetMidY(bounds))];
_colorDotLayer.path = path.CGPath;
}
- (void)awakeFromNib {
[super awakeFromNib];
self.annotationColor = [UIColor redColor];
}
#end
Result:
I think is more easy than this solutions:
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:(CGPoint){20, 0}];
[path addLineToPoint:(CGPoint){40, 40}];
[path addLineToPoint:(CGPoint){0, 40}];
[path addLineToPoint:(CGPoint){20, 0}];
// Create a CAShapeLayer with this triangular path
// Same size as the original imageView
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.viewTriangleCallout.bounds;
mask.path = path.CGPath;
This is my white triangle:
You can change points or rotate if you want:
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:(CGPoint){0, 0}];
[path addLineToPoint:(CGPoint){40, 0}];
[path addLineToPoint:(CGPoint){20, 20}];
[path addLineToPoint:(CGPoint){0, 0}];
// Create a CAShapeLayer with this triangular path
// Same size as the original imageView
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.viewTriangleCallout.bounds;
mask.path = path.CGPath;
Example code, it is based on this SO Answer which draws stars:
#implementation TriangleView
-(void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
int sides = 3;
double size = 100.0;
CGPoint center = CGPointMake(160.0, 100.0);
double radius = size / 2.0;
double theta = 2.0 * M_PI / sides;
CGContextMoveToPoint(context, center.x, center.y-radius);
for (NSUInteger k=1; k<sides; k++) {
float x = radius * sin(k * theta);
float y = radius * cos(k * theta);
CGContextAddLineToPoint(context, center.x+x, center.y-y);
}
CGContextClosePath(context);
CGContextFillPath(context); // Choose for a filled triangle
// CGContextSetLineWidth(context, 2); // Choose for a unfilled triangle
// CGContextStrokePath(context); // Choose for a unfilled triangle
}
#end
Use UIBezeierPaths
CGFloat radius = 20;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, (center.x + bottomLeft.x) / 2, (center.y + bottomLeft.y) / 2);
CGPathAddArcToPoint(path, NULL, bottomLeft.x, bottomLeft.y, bottomRight.x, bottomRight.y, radius);
CGPathAddArcToPoint(path, NULL, bottomRight.x, bottomRight.y, center.x, center.y, radius);
CGPathAddArcToPoint(path, NULL, center.x, center.y, bottomLeft.x, bottomLeft.y, radius);
CGPathCloseSubpath(path);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithCGPath:path];
CGPathRelease(path);

how to draw an arc with line using UIBezierPath

I am trying to draw shape shown in figure. Background is white.. Hope it is visible to you..
I am using bezier path to draw this. I have provided bounds to shape as shown by blue border.
So far I am successfully able to draw just two lines(shown in green). I have to draw the one with red further.
I am unable to draw arc from this point. I can't understand how to pass correct parameters to addArcWithCenter.
Code
-(void) drawRect:(CGRect)rect
{
//declare and instantiate the UIBezierPath object
aPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect))];
// Draw some lines.
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect))];
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect) - 40)];
[aPath addArcWithCenter:self.center radius:40 startAngle:3 *(M_PI / 2) endAngle:M_PI clockwise:NO];
//set the line width
aPath.lineWidth = 2;
//set the stoke color
[[UIColor greenColor] setStroke];
//draw the path
[aPath stroke];
}
I am new to core graphics. Please be lenient over me.. Thanks..
Try with this (as you can see, I've used addQuadCurveToPoint a variant of addCurveToPoint proposed by #wain - ask google for addCurveToPoint and switch to picture search to see how it work ) :
-(void) drawRect:(CGRect)rect
{
UIBezierPath * aPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect))];
// Draw some lines.
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect))];
//changes start here !
//the point look to be at 80% down
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect) * .8)];
//1st arc
//The end point look to be at 1/4 at left, bottom
CGPoint p = CGPointMake(CGRectGetMaxX(rect) / 4, CGRectGetMaxY(rect));
CGPoint cp = CGPointMake( (CGRectGetMaxX(rect) / 4) + ((CGRectGetMaxX(rect) - (CGRectGetMaxX(rect) / 4)) / 2) , CGRectGetMaxY(rect) * .8);
[aPath addQuadCurveToPoint:p controlPoint:cp];
//2nd arc
//The end point look to be at 80% downt at left,
CGPoint p2 = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect) * .8);
CGPoint cp2 = CGPointMake( (CGRectGetMaxX(rect) / 4) / 2 , CGRectGetMaxY(rect) * .8);
[aPath addQuadCurveToPoint:p2 controlPoint:cp2];
//close the path
[aPath closePath];
//set the line width
aPath.lineWidth = 2;
//set the stoke color
[[UIColor greenColor] setStroke];
//draw the path
[aPath stroke];
}

UIBezierPath with multiples arcs

Hiiii
I'm trying to draw in a view an arc with dynamic width.
I have built an ARRAY with several UIBezierPath with arcs then I draw one after the other. this is the code:
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGFloat radious;
if (self.bounds.size.width < self.bounds.size.height) {
radious = self.bounds.size.width / 2;
}
else{
radious = self.bounds.size.height / 2;
}
float oneGradeInRadians = (float)(2 * M_PI) / 360.f;
float radiandToDraw = (float)self.finalAngleRadians - self.initialAngleRadians;
float splitMeasure = oneGradeInRadians;
int numberOfArcs = radiandToDraw / splitMeasure;
NSMutableArray *arrayOfBeziersPaths = [NSMutableArray arrayWithCapacity:numberOfArcs];
for (int i = 0; i < numberOfArcs; i++) {
float startAngle = self.initialAngleRadians + (i * splitMeasure);
float endAngle = self.initialAngleRadians +((i + 1) * splitMeasure);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2) radius:radious - self.widthLine.floatValue startAngle:startAngle endAngle:endAngle clockwise:YES];
bezierPath.lineWidth = self.widthLine.floatValue + i/20;
float hue = (float)(i / 3.f);
UIColor *color = [UIColor colorWithHue:hue/360.0 saturation:1 brightness:1 alpha:1];
[color setStroke];
[arrayOfBeziersPaths addObject:bezierPath];
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineJoin(context, kCGLineJoinMiter);
//We saved the context
CGContextSaveGState(context);
for (int i = 0; i < numberOfArcs; i++) {
[(UIBezierPath *)[arrayOfBeziersPaths objectAtIndex:i] stroke];
[(UIBezierPath *)[arrayOfBeziersPaths objectAtIndex:i] fill];
}
//Restore the contex
CGContextRestoreGState(context);
}
In this way I get the right shape but, also I get an annoying lines between the arcs:
I think the problem may be a property to change between arcs, but I'm totally lost, or maybe there is another better way to build this.
I tried creating several UIBezierPath paths and I added them to an unique UIBezierPath, then I stoke and fill that path. I didn't get the annoying lines, but the problem is I can not modify the line width, so I can not get the same effect.
Any idea? thanks
dont create many such paths. just create two arcs (inner circle, exterior circle) and two straight lines joining the ends. then fill the path.
Add below code in a viewDidLoad of an empty viewController and check.
- (void)viewDidLoad
{
[super viewDidLoad];
CGFloat k =0.5522847498;
UIBezierPath *path =[UIBezierPath bezierPath];
CGFloat radius=130;
[path addArcWithCenter:CGPointMake(0, 0) radius:radius startAngle:M_PI_2 endAngle:M_PI clockwise:NO];
CGFloat start=10;
CGFloat increment=5;
[path addLineToPoint:CGPointMake(-radius-start, 0)];
[path addCurveToPoint:CGPointMake(0, -radius-start-increment) controlPoint1:CGPointMake(-radius-start, -(radius +start)*k) controlPoint2:CGPointMake(-(radius+start)*k, -radius-start-increment)];
[path addCurveToPoint:CGPointMake(radius+start+2*increment, 0) controlPoint1:CGPointMake((radius+start+increment)*k, -radius-start-increment) controlPoint2:CGPointMake(radius+start+2*increment, (-radius-start-increment)*k)];
[path addCurveToPoint:CGPointMake(0, radius+start+3*increment) controlPoint1:CGPointMake(radius+start+2*increment, (radius+start+2*increment)*k) controlPoint2:CGPointMake((radius+start+2*increment)*k,radius+start+3*increment)];
[path addLineToPoint:CGPointMake(0,radius)];
CAShapeLayer *layer =[CAShapeLayer layer];
[layer setFrame:CGRectMake(150, 200, 300, 300)];
[layer setFillColor:[UIColor greenColor].CGColor];
[layer setStrokeColor:[UIColor blackColor].CGColor];
[layer setPath:path.CGPath];
[self.view.layer addSublayer:layer];
}
It produced result like,
The problem here is that you’ve chosen a crazy approach to drawing the shape you’re after. If you take a look at it, you’ll see that it’s actually a filled region bounded on the outside by a circular arc, and on the inner edge by a spiral.
What you should do, therefore, is create a single NSBezierPath, add the outer circular arc to it, then add a line to the start of your spiral, append a spiral (you’ll want to approximate it with Bézier segments) and finally call -closePath. After that, you can -fill the path and you’ll get a good looking result rather than the mess you have above.

UIBezierPath and applytransform

I am trying to implement a custom UIView which is basically a pie menu (something like a cake divided into slices).
For that I am trying to draw a circle and a series of lines from the center, like the rays in a chart's wheel.
I have successfully drawn the circle and and I would now like to draw the lines dividing the circle in slices.
This is what I have so far:
-(void)drawRect:(CGRect)rect{
[[UIColor blackColor] setStroke];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat minDim = (rect.size.width < rect.size.height) ? rect.size.width : rect.size.height;
CGRect circleRect = CGRectMake(0, rect.size.height/2-minDim/2, minDim, minDim);
CGContextAddEllipseInRect(ctx, circleRect);
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor yellowColor] CGColor]));
CGContextFillPath(ctx);
CGPoint start = CGPointMake(0, rect.size.height/2);
CGPoint end = CGPointMake(rect.size.width, rect.size.height/2);
for (int i = 0; i < MaxSlices(6); i++){
CGFloat degrees = 1.0*i*(180/MaxSlices(6));
CGAffineTransform rot = CGAffineTransformMakeRotation(degreesToRadians(degrees));
UIBezierPath *path = [self pathFrom:start to:end];
[path applyTransform:rot];
}
}
- (UIBezierPath *) pathFrom:(CGPoint) start to:(CGPoint) end{
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5;
[aPath moveToPoint:start];
[aPath addLineToPoint:end];
[aPath closePath];
[aPath stroke];
return aPath;
}
The problem is that applyTransform on the path doesn't seem to do anything. The first path gest drawn correctly the and the following ones are unaffected by the rotation. Basically what I see is just one path. Check the screen shot here http://img837.imageshack.us/img837/9757/iossimulatorscreenshotf.png
Thank you for your help!
You're drawing the path (with stroke) before you transform it. A path is just a mathematical representation. It isn't the line "on the screen." You can't move what you've already drawn by modifying the data about it.
Just move the [aPath stroke] out of pathFrom:to: and put it after the applyTransform:.

Resources