Core Graphics - drawing a line at an angle - iphone

I've been searching struggling with this for a while now and need some help. I just want to draw 25 lines from the centre of my display (160,200) at 14.4 degrees separation. I have been using this line of code in a for loop where x is the 14.4 degree multiplier -
UIImage*backgroundImage = [UIImage imageNamed:#"Primate Background Only.png"];
[backgroundImage drawInRect:CGRectMake(0, 0, 320, 480)];
// Draw Outer Circle
rect = CGRectMake(0.0, 35.0, 320.0, 320.0);
CGContextRef contextRef = UIGraphicsGetCurrentContext(); // Get the contextRef
CGContextSetLineWidth (contextRef, 0.5); // Set the border width
CGContextSetRGBFillColor (contextRef, (219.0f/255.0f), (219.0f/255.0f), (219.0f/255.0f), 0.05f); // Set the circle fill color to GREEN
CGContextSetRGBStrokeColor (contextRef, 0.0, 0.0, 0.0, 0.2); // Set the circle border color to BLACK
CGContextFillEllipseInRect (contextRef, rect); // Fill the circle with the fill color
CGContextStrokeEllipseInRect (contextRef, rect); // Draw the circle border
// Draw Inner Circle
rect = CGRectMake(25.0, 60.0, 270.0, 270.0); // Get the contextRef
CGContextSetLineWidth (contextRef, 0.5); // Set the border width
CGContextSetRGBFillColor (contextRef, (219.0f/255.0f), (219.0f/255.0f), (219.0f/255.0f), 0.25f);
CGContextSetRGBStrokeColor (contextRef, 0.0, 0.0, 0.0, 0.2); // Set the circle border color to BLACK
CGContextFillEllipseInRect (contextRef, rect); // Fill the circle with the fill color
CGContextStrokeEllipseInRect (contextRef, rect);
// Draw Segments
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, 0.0);
for (x=1; x<26; x++) {
CGContextSetLineWidth (context, 0.5);
CGContextSetRGBStrokeColor (context, 0.0, 0.0, 0.0, 0.25);
CGContextMoveToPoint (context, 160, 200);
CGContextAddLineToPoint (context, (160.0 * (cos((x*14.4)*(M_PI/180)))), (160.0 * (sin((x*14.4)*(M_PI/180))))); // The angle is in degrees
CGContextAddLineToPoint (context, 200, 65);
CGContextAddLineToPoint (context, 160, 200);
CGContextStrokePath(context); // Why is this not showing both line color and infill?
CGContextSetFillColorWithColor (context, [UIColor whiteColor].CGColor);
CGContextFillPath (context);
CGContextRef context = UIGraphicsGetCurrentContext();
}
(I intended to post an image here but it won't permit me!)
Can someone please correct my trig functions. This is meant to draw 25 lines clockwise from 12:00 o'clock to 24:00. Instead it draws backwards only 90 degrees then returns, all lines are way out in length also.
Very grateful
Above is a bigger sample of the code used to draw tow outer circles and the interior segments as requested. I'll try and upload the image next.

Your main problem is this line of code:
CGContextAddLineToPoint(context, (160.0 * (cos((x*14.4)*(M_PI/180)))),
(160.0 * (sin((x*14.4)*(M_PI/180)))));
it should be:
CGContextAddLineToPoint(context, 160 + (160.0 * (cos((x*14.4)*(M_PI/180)))),
200 + (160.0 * (sin((x*14.4)*(M_PI/180)))));
As you had originally written it the lines were be drawn relative to 0,0 but you want to draw relative to your center point (160, 200).
The next 2 lines are also a little suspect:
CGContextAddLineToPoint (context, 200, 65);
CGContextAddLineToPoint (context, 160, 200);
It is not clear to me what you were trying to do here, but this would end up drawing a line from the end of each arm to a fixed point (200,65) and from there back to you center point, which is almost certainly not what you intended! Try commenting out these lines, confirm that the "arms" are being drawn correctly and take it from there...
Hope this is clear
If you make these corrections your screen will look something like this:

Related

How to draw a full circle with image

I'm pretty new with core graphics. I need to draw a full circle. How do I go about it? I currently have a masked circle.
I referred to this example.
//Use the draw rect to draw the Background, the Circle and the Handle
-(void)drawRect:(CGRect)rect{
[super drawRect:rect];
CGContextRef ctx = UIGraphicsGetCurrentContext();
/** Draw the Background **/
//Create the path
CGContextAddArc(ctx, self.frame.size.width/2, self.frame.size.height/2, radius, 0, M_PI *2, 0);
// CGContextFillEllipseInRect(ctx, CGRectMake(self.frame.size.height/2, self.frame.size.width/2, 100, 100));
// CGContextSetRGBFillColor(ctx, 0.5, 0.5, 0.5, 1.0);
//Set the stroke color to black
[[UIColor greenColor]setStroke];
//Define line width and cap
CGContextSetLineWidth(ctx, TB_BACKGROUND_WIDTH);
CGContextSetLineCap(ctx, kCGLineCapButt);
CGContextDrawPath(ctx, kCGPathStroke);
UIGraphicsBeginImageContext(CGSizeMake(TB_SLIDER_SIZE,TB_SLIDER_SIZE));
CGContextRef imageCtx = UIGraphicsGetCurrentContext();
CGContextAddArc(imageCtx, self.frame.size.width/2 , self.frame.size.height/2, radius, 0, ToRad(self.self.startAngle), 0);
[[UIColor redColor]set];
CGContextSetLineWidth(imageCtx, TB_LINE_WIDTH);
CGContextDrawPath(imageCtx, kCGPathStroke);
//save the context content into the image mask
CGImageRef mask = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
UIGraphicsEndImageContext();
CGContextSaveGState(ctx);
CGContextClipToMask(ctx, self.bounds, mask);
CGImageRelease(mask);
//list of components
CGFloat components[8] = {
0.0, 0.0, 1.0, 1.0, // Start color - Blue
1.0, 1.0, 1.0, 1.0 }; // End color - Violet
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, components, NULL, 2);
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
//Gradient direction
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
//Draw the gradient
CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(ctx);
/** Draw the handle **/
[self drawTheHandle:ctx];
}
CGContextDrawPath(imageCtx, kCGPathFill);
make the backgroup width and line width to 140 and it works!!
#define TB_BACKGROUND_WIDTH 140 //The width of the dark background
#define TB_LINE_WIDTH 140 //The width of the active area (the gradient) and the width of the handle

Avoiding Stretching Stroke when Using CGContextScaleCTM

I have a shape that I'm drawing in drawRect which is stored in a CGMutablePathRef (shapeMutablePath). Each time drawRect is called, the shape is stretched to fit the screen with a stroke border around it. I am wondering, how is it possible to draw the stroke border without also stretching it? ie stretching the shapeMutablePath, then drawing the stroke border around it so it's the same width every time it's drawn? I've tried changing the order of the scale and the add and draw path to no avail.
- (void) drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetRGBFillColor(context, 1.0000, 1.0000, 1.0000, 1.0000);
CGContextSetRGBStrokeColor(context,0.0000,0.0000,0.0000,1.0000);
CGContextSetLineWidth(context, DialogueTextViewLineWidth);
CGContextScaleCTM (context, self.frame.size.width / self.shapeMutablePathWidth, self.frame.size.height / self.shapeMutablePathHeight);
CGContextAddPath(context, self.shapeMutablePath);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextRestoreGState(context);
}
Instead of scaling the CTM and using the original path:
CGContextScaleCTM (context, self.frame.size.width / self.shapeMutablePathWidth, self.frame.size.height / self.shapeMutablePathHeight);
CGContextAddPath(context, self.shapeMutablePath);
... create a transformed path and use that instead:
CGAffineTransform trn = CGAffineTransformMakeScale(self.bounds.size.width / self.shapeMutablePathWidth, self.bounds.size.height / self.shapeMutablePathHeight);
CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(self.shapeMutablePath, &trn);
CGContextAddPath(context, transformedPath);
CGPathRelease(transformedPath);
This will fill and stroke the same (scaled) area but the transform will not affect the stroke width.
B.t.w. You would typically use the bounds, not the frame's size to calculate the scale.

CGContextDrawImage when shifting x offset

So I have the following code:
CGContextDrawImage(context, CGRectMake(100, 0, 220, self.image.size.height), self.image.CGImage);
basically I am asking CG to draw the image 100 px to the right.. now this works fine.. however to the left of the image I see a white background. How do I change this background to some other color? Say I want a black blackground
Before drawing the image, fill the rect with the desired color:
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextFillRect(context, CGRectMake(0, 0, self.image.size.width + 100, self.image.size.height)); //I suppose your rect's width is as much as image's width +100
//Then draw your image
CGContextDrawImage(context, CGRectMake(100, 0, 220, self.image.size.height), self.image.CGImage);
Note: Make sure the rect's you're drawing into width is at least the image's width + 100

How to fill the shapes with color

I am new to Objective-C and iOS development. I have a view with some figures drawn by core drawing. Now I want to fill those shapes with color and I don't know the path or context of shape. Does Objective-C have any function like flood-fill or put-pixel so that by having only the stroke color I can fill any shape inside my view.
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {1.0, 0.0, 0.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 50, 0);
CGContextAddLineToPoint(context, 0,320);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetRGBFillColor(context, 0, 255, 0, 1.0);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
This will make a circle and a square with some common region. I want a particular region to fill with color when a user taps that region.
So you are looking for flood fill in Objective C.
This is my implementation of Scan Line Flood Fill Algorithm.
Github : UIImageScanlineFloodfill
If you want to learn basic of flood fill:
Lode's Computer Graphics Tutorial Flood Fill
I hope this will help you.
Put your drawing code in the question and I can give you a specific answer.
Normally you just need to set a fill color using
[[UIColor redColor] setFill];
And any shapes you draw your core graphics will be filled with that color automatically.
Try this command:-
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
Core Graphics is closely tied to UIView and its drawRect: method and has a C interface. As you point out, you always draw in the current graphics context. I can think of 2 approaches: (1) When the user taps myView, set a property like myView.pointTapped, and in drawRect: find the shape to fill, set a fill color, and fill the closed path using GGGeometry methods.
There is an objective-C alternative: (2) Take a look at UIBezierPath. It's not as comprehensive as drawing in Core Graphics but it can be used in your ViewController implementation.

How to draw a concentric circle in iphone?

I want to draw a ring. Ring should filled in a outer circle. I referred a documentation http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html#//apple_ref/doc/uid/TP30001066-CH211-TPXREF101. But still had problem to get the outcome. Here is the code.
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextClearRect(ctx, rect);
CGContextSetRGBFillColor(ctx, 0.0, 255.0, 1.0, 1.0);CGContextFillPath(ctx);
CGContextStrokeEllipseInRect(ctx, CGRectMake(125, 125, 150, 150));
CGContextBeginPath(ctx);
CGContextEOFillPath(ctx);
CGContextFillEllipseInRect(ctx, CGRectMake(100, 100, 200, 200));
You need something more like this:
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, rect);
CGContextAddEllipseInRect(ctx,
CGRectMake(
rect.origin.x + 10,
rect.origin.y + 10,
rect.size.width - 20,
rect.size.height - 20));
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor blueColor] CGColor]));
CGContextEOFillPath(ctx);
}
This will add two ellipses to your current path (one being smaller than the other, but centered around the same point). EOFillPath will essentially "subtract" the inner ellipse from the outer ellipse when it fills the path.
To create "concentric" circles, if that's really what you wanted, you can simply repeat this for more - continually smaller - ellipses.