RotateCTM makes graphics disappear, Quartz 2D - iphone

First off, I am a quartz 2d noob. I have a pie chart, and basically want to make a line coming out of it diagonally, in the northeast quadrant, then go horizontal to the right, and have a label explaining what that section is. So, I have this code that draws the diagonal line. The line draws to the southeast. I expect that based on the iPhone origin being in the northwest quadrant. So I thought I could rotate my CTM first by 3pi/2, and then have that same code work. However, when I uncomment the CGContextRotateCTM() line, I get no line. I'm not sure what is happening here and where the logic error is. Thanks.
CGPoint circleCenter = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]);
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, LINE_WIDTH);
CGContextBeginPath(context);
// CGContextRotateCTM(context, 3 * M_PI / 2);
CGContextMoveToPoint(context, circleCenter.x + self.CircleRadius / 2, circleCenter.y + self.CircleRadius / 2);
CGContextAddLineToPoint(context, circleCenter.x + self.CircleRadius / 2 + LINE_LENGTH, circleCenter.y + self.CircleRadius / 2 + LINE_LENGTH);
CGContextStrokePath(context);

It seems you are rotating your line out of sight. Always keep the center in mind that you rotate around - maybe also translate your CTM first.
Edit: To check, you might want to try very small rotations incrementally and watch where your line goes.

Related

Clipping inverse drawing?

I'm want to remove the blue part of the following images. How do I clip the inverse of the drawing? (I believe that's the correct way to ask the question)
Example code for Triangle: (If there's better triangle code, I'd accept that too!;)
int lineWidth = 4;
int w = size.size.width;
int h = size.size.height - lineWidth;
CGPoint top = CGPointMake(0+(w/2)+.5, 0);
CGContextClipToRect(ctx, CGRectMake(0, 0, w, h));
CGContextStrokePath(ctx);
CGContextMoveToPoint(ctx, top.x, top.y);
CGContextAddLineToPoint(ctx, top.x + (w/2), top.y + h );
CGContextAddLineToPoint(ctx, top.x - (w/2), top.y + h );
CGContextAddLineToPoint(ctx, top.x, top.y);
CGContextFillPath(ctx);
CGContextSetLineWidth(ctx, lineWidth);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextMoveToPoint(ctx, top.x, top.y);
CGContextAddLineToPoint(ctx, top.x + (w/2), top.y + h );
CGContextAddLineToPoint(ctx, top.x - (w/2), top.y + h );
CGContextAddLineToPoint(ctx, top.x, top.y);
CGContextStrokePath(ctx);
An easy solution is to use UIBazierPath. Draw a Bazier Path according to your intentions. Then call [path addClip] method. It'll clip all the outside the closed path.
For example following code makes your view round cornered.
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(6.0, 6.0)];
[path addClip];
To clip the inverse of any path just add an enclosing rect to your clip.
In this case, if I get you right, you want to clip around the red stroke of the shapes. Generally, that's not an easy task in quartz due to the line width of the stroked path. Of course, for these two shapes, we can compute the outline of the red stroke and clip around that. But a general solution would need a way to calculate the encompassing path, including the line width.
There are other ways that include bitmap masks—but the best solution would depend on what exactly are you drawing. I just had a similar problem which I could very elegantly and efficiently solve using a specialized quartz blend mode. This depends very much on the contents of the centext before drawing and how the result should be blended with the rest of the UI.

How to animate an Arc? [duplicate]

How would I animate a circle on the iPhone so that the arc starts at "0 degrees" and ends at "360 degrees"?
Advance Thanks,
Sat
You need to read the Quartz 2D Programming Guide's section on arcs. (I am assuming you are creating an app with the Cocoa Touch API, not a web app.) You also need to know how to set up a custom animation. You will have to create a custom UIView or CALayer to do the drawing, and create a property (arc degree) that can be animated with a CAAnimation object. Alternatively, you can control the animation using an NSTimer instead. You pretty much have to have a grasp of these classes (and others) to pull this off.
Here you can find a great sample code about circle animation:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/24152-draw-animated-circle-iphone-using-core-graphics.html
you should read the documentation that Felixyz provided and if you want an example of how to animate the circle have a look over the MBProgressHUD at this link link text. The loader has two modes one with a UIViewActivityIndicator and a progress indicator (a filling circle that it is animated from 0 to 360 degress) i think the last mode is what you want.
the fallowing code is from copy/paste from that implementation that animates the circle:
- (void)drawRect:(CGRect)rect {
CGRect allRect = self.bounds;
CGRect circleRect = CGRectMake(allRect.origin.x + 2, allRect.origin.y + 2,
allRect.size.width - 4, allRect.size.height - 4);
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw background
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); // white
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.1); // translucent white
CGContextSetLineWidth(context, 2.0);
CGContextFillEllipseInRect(context, circleRect);
CGContextStrokeEllipseInRect(context, circleRect);
// Draw progress
float x = (allRect.size.width / 2);
float y = (allRect.size.height / 2);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); // white
CGContextMoveToPoint(context, x, y);
CGContextAddArc(context, x, y, (allRect.size.width - 4) / 2, -(PI / 2),
(self.progress * 2 * PI) - PI / 2, 0);
CGContextClosePath(context); CGContextFillPath(context);
}
but read the documentation first! hope it helps

I need to draw a line on a view, and have the line be straight no matter what, but dynamic in length

Ok I need to implement a simple measuring tool for an iPad app I am working on. I don't have any experience with drawing, so I am really struggling. When the user presses down on the view (in measuring mode) the line's origin starts. I need to then be able to draw a line to wherever the user drags their finger, as they are dragging their finger, and have it be straight the entire time too.
I have the logic that calculates the distance between two points working based on two UITapGestureRecognizers, but I am thinking I will need to implement the touchesBegan/Ended methods instead.
How can I draw a line as the user drags, and make it stay straight the entire time?
I just need a point in the right direction.
Thanks!!
Check out a good tutorial like this.
Skip to the section on drawing lines:
void draw1PxStroke(CGContextRef context, CGPoint startPoint, CGPoint endPoint,
CGColorRef color) {
CGContextSaveGState(context);
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5);
CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
and then here is the call to that method:
// Add in color section
CGColorRef separatorColor = [UIColor colorWithRed:208.0/255.0 green:208.0/255.0
blue:208.0/255.0 alpha:1.0].CGColor;
// Add at bottom
CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(100, 20);
draw1PxStroke(context, startPoint, endPoint, separatorColor);

UIView drawRect drawing lines of wrong width

I'm trying to add a little red line on the bottom of my UIView.
I want the line to be a 1px line.
Can someone tell me why the following code:
- (void)drawRect:(CGRect)rect {
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetRGBFillColor(currentContext, 0.0f, 0.0f, 0.0f, 1.0f);
CGContextFillRect(currentContext, RECT(0, 0, rect.size.width, rect.size.height - 8));
CGContextSetLineWidth(currentContext, 1);
CGContextSetRGBStrokeColor(currentContext, 1.0f, 0.0f, 0.0f, 1.0f);
CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, 0, rect.size.height - 7);
CGContextAddLineToPoint(currentContext, rect.size.width, rect.size.height - 7);
CGContextStrokePath(currentContext);
CGContextRestoreGState(currentContext);
}
Draws a line that spans 2px in height?
The integral coordinates indicate places half-way between pixels; that is, (0,0) is in the upper-left corner, above and to the left of the upper-left pixel; similarly, (1,0) is between the first and second pixels; finally, (0.5,0.5) is at the center of the upper-left pixel.
According to the documentation for CGContextSetLineWidth, "when stroked, the line straddles the path, with half of the total width on either side." Thus, if the path is lying precisely in between the pixels, the line will be stroked half on one row of pixels, half on the other.
Hence, to get a sharp pixel line, you must offset your coordinates by half a pixel: for your x coordinate, use rect.size.height - 7.5 instead of - 7.
By the way, when drawing rectangles, it is handy to use CGRectInset(rect, 0.5, 0.5) to achieve this.
Do you use an iPhone 4? The iPhone 4 uses a coordinate system with a scale factor of 2. So you would need to set the line width to 0.5 in order to get what you want.
(The coordinate system is set up that way so the same code produces the same output on all models.)
Lines are by default drawn antialiased (unless you configure otherwise). Thus any line that's not strictly vertical or horizontal and starting and ending on a pixel will likely partially cover multiple pixels in some rows and/or columns, making it look like a wider grey line instead of a thin higher-contrast line.

Arc / Circle animation in iphone

How would I animate a circle on the iPhone so that the arc starts at "0 degrees" and ends at "360 degrees"?
Advance Thanks,
Sat
You need to read the Quartz 2D Programming Guide's section on arcs. (I am assuming you are creating an app with the Cocoa Touch API, not a web app.) You also need to know how to set up a custom animation. You will have to create a custom UIView or CALayer to do the drawing, and create a property (arc degree) that can be animated with a CAAnimation object. Alternatively, you can control the animation using an NSTimer instead. You pretty much have to have a grasp of these classes (and others) to pull this off.
Here you can find a great sample code about circle animation:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/24152-draw-animated-circle-iphone-using-core-graphics.html
you should read the documentation that Felixyz provided and if you want an example of how to animate the circle have a look over the MBProgressHUD at this link link text. The loader has two modes one with a UIViewActivityIndicator and a progress indicator (a filling circle that it is animated from 0 to 360 degress) i think the last mode is what you want.
the fallowing code is from copy/paste from that implementation that animates the circle:
- (void)drawRect:(CGRect)rect {
CGRect allRect = self.bounds;
CGRect circleRect = CGRectMake(allRect.origin.x + 2, allRect.origin.y + 2,
allRect.size.width - 4, allRect.size.height - 4);
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw background
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); // white
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.1); // translucent white
CGContextSetLineWidth(context, 2.0);
CGContextFillEllipseInRect(context, circleRect);
CGContextStrokeEllipseInRect(context, circleRect);
// Draw progress
float x = (allRect.size.width / 2);
float y = (allRect.size.height / 2);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); // white
CGContextMoveToPoint(context, x, y);
CGContextAddArc(context, x, y, (allRect.size.width - 4) / 2, -(PI / 2),
(self.progress * 2 * PI) - PI / 2, 0);
CGContextClosePath(context); CGContextFillPath(context);
}
but read the documentation first! hope it helps