CGContextAddEllipse - overlapping get's clipped - Quartz - objective-c

I like to draw a glass with a few Elements
- Top Ellipse
- Bottom Ellipse
- and the Lines Inbetween
Next, it should be filled with a Gradient. The Elements work, but at the point, where the middle of the glass comes in touch with the top or bottom ellipse the area get's clipped.
- (void)drawRect:(CGRect)rect
{
CGPoint c = self.center;
// Drawing code
CGContextRef cx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(cx, 1.0);
[[UIColor whiteColor] setStroke];
// DrawTheShapeOfTheGlass
CGContextBeginPath(cx);
// Top and Bottom Ellipse
CGContextAddEllipseInRect(cx, CGRectMake(0, 0, 100, 20));
CGContextAddEllipseInRect(cx, CGRectMake(10, 90, 80, 20));
// Define the points for the Area inbetween
CGPoint points[] = { {0.0,10.0},{10.0,100.0},{90.0,100.0},{100.0,10.0} };
CGContextAddLines(cx, points, 4);
CGContextClosePath(cx);
// Clip, that's only the Clipped-Area wil be filled with the Gradient
CGContextClip(cx);
// CreateAndDraw the Gradient
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat colorSpace[] = {1.0f, 1.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f };
CGFloat locations[] = { 0.0, 1.0 };
CGGradientRef myGradient = CGGradientCreateWithColorComponents(rgbColorSpace, colorSpace, locations, 2);
CGPoint s = CGPointMake(0, 0);
CGPoint e = CGPointMake(100, 100);
CGContextDrawLinearGradient(cx, myGradient, s, e, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGColorSpaceRelease(rgbColorSpace);
CGGradientRelease(myGradient);
}
Here how it looks like:
Is there any possibility to "fill" the whole ellipse? I played around with BlendModes but it didn't help.
Thanks

Try replacing the points[] initialization code with the following...
CGPoint points[] = {{0.0,10.0},{100.0,10.0},{90.0,100.0},{10.0,100.0}};
CoreGraphics uses the non-zero winding count rule to determine how to fill a path. Since ellipses are drawn clockwise and your trapezoid was drawn counter clockwise, the overlapping regions were not filled. Changing the drawing order of the trapezoid to clockwise will result in an object that is completely filled.

Related

need assistance regarding growing & shrinking circle from centre in quartz-2d

I am currently working on drawing app, in which have a slider to increase and decrease line width. I just want to do a simple thing that a circle in front of slider to present a width. I easily did that but its not growing and shrinking from centre, its growing and shrinking from top x, y, here is the code
- (UIImage *)circleOnImage:(int)size
{
UIGraphicsBeginImageContext(CGSizeMake(25, 25));
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor blackColor] setFill];
CGContextTranslateCTM(ctx, 12, 12);//also try to change the coordinate but didn't work
CGRect circleRect = CGRectMake(0, 0, size, size);
CGContextFillEllipseInRect(ctx, circleRect);
UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return retImage;
}
Try
CGContextTranslateCTM(ctx, 12.5, 12.5);
CGRect circleRect = CGRectMake(-size/2., -size/2., size, size);

drawing dotted lines from UIViewController

I have a UIViewController which has a UIView in it and I want to draw a straight dotted line on it. What is the easiest and performant way to do this? How do I do this? It will just be a straight horizontal dotted line of width 150 with gray color. I've looked around and it seems that using
CGContextSetLineDash is the solution and here's what I have so far:
-(void) drawRect:(CGRect) rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 100);
CGFloat dashes[] = {1,1};
CGContextSetLineDash(context, 2.0, dashes, 2);
CGContextStrokePath(context);
}
CGContextStrokePath draws the current path, however, you never add any path to your context, so nothing is drawn.
Add the following two lines before your CGContextStrokePath call and you should see something:
CGContextMoveToPoint(context, 0, self.bounds.size.height * 0.5);
CGContextAddLineToPoint(context, self.bounds.size.width, self.bounds.size.height * 0.5);
If you haven't already set your stroke color, you should also add something like this (50% gray):
CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
I'm not sure if the result is really what you want, a 100 point dotted line with a pattern of {1, 1} will look more like an rectangle with a pinstripe pattern than like a dotted line. If you want your dots to be circles, you will have to draw those manually in some sort of loop.
Try this:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, 2.0);
CGFloat lengths[] = {0, 8};
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineDash(context, 0.0f, lengths, 2);
CGContextMoveToPoint(context, 10, 10);
CGContextAddLineToPoint(context, 200, 10);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);

Objective-C Draw a Circle with a Ring shape

I wrote this class that draws a animated progress with a circle (it draws a circular sector based on a float progress)
#implementation MXMProgressView
#synthesize progress;
- (id)initWithDefaultSize {
int circleOffset = 45.0f;
self = [super initWithFrame:CGRectMake(0.0f,
0.0f,
135.0f + circleOffset,
135.0f + circleOffset)];
self.backgroundColor = [UIColor clearColor];
return self;
}
- (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();
// background image
//UIImage *image = [UIImage imageNamed:#"loader_disc_hover.png"];
//[image drawInRect:circleRect];
// Orange: E27006
CGContextSetRGBFillColor(context,
((CGFloat)0xE2/(CGFloat)0xFF),
((CGFloat)0x70/(CGFloat)0xFF),
((CGFloat)0x06/(CGFloat)0xFF),
0.01f); // fill
//CGContextSetLineWidth(context, 2.0);
CGContextFillEllipseInRect(context, circleRect);
//CGContextStrokeEllipseInRect(context, circleRect);
// Draw progress
float x = (allRect.size.width / 2);
float y = (allRect.size.height / 2);
// Orange: E27006
CGContextSetRGBFillColor(context,
((CGFloat)0xE2/(CGFloat)0xFF),
((CGFloat)0x70/(CGFloat)0xFF),
((CGFloat)0x06/(CGFloat)0xFF),
1.0f); // progress
CGContextMoveToPoint(context, x, y);
CGContextAddArc(context, x, y, (allRect.size.width - 4) / 2, -M_PI_2, (self.progress * 2 * M_PI) - M_PI_2, 0);
CGContextClosePath(context);
CGContextFillPath(context);
}
#end
Now what I want to do I to draw a ring shape with the same progress animation, instead of filling the full circle, so a circular sector again not starting from the center of the circle.
I tried with CGContextAddEllipseInRect and the CGContextEOFillPath(context);
with no success.
I think you'll need to construct a more complex path, something like:
// Move to start point of outer arc (which might not be required)
CGContextMoveToPoint(context, x+outerRadius*cos(startAngle), y+outerRadius*sin(startAngle));
// Add outer arc to path (counterclockwise)
CGContextAddArc(context, x, y, outerRadius, startAngle, endAngle, 0);
// move *inward* to start point of inner arc
CGContextMoveToPoint(context, x+innerRadius*cos(endAngle), y+innerRadius*sin(endAngle));
// Add inner arc to path (clockwise)
CGContextAddArc(context, x, y, innerRadius, endAngle, StartAngle, 1);
// Close the path from end of inner arc to start of outer arc
CGContextClosePath(context);
Note: I haven't tried the above code myself
Cheap and nasty solution:
Draw a solid circle that is smaller than the original circle by the thickness of the ring you want to draw.
Draw this circle on top of the original circle, all that you will see animating is the ring.

ios CCLabelTTF colored subclass with Core Text

Good day to all.
At the moment I am trying to implement CCLabelTTF subclass with suppport of NSAttributedString to get multi-colored label. And I am hampered by lack of CoreText and CoreGraphics knowledge.
After reading few guides I, created CCTexture2D category to create texture using NSAttributedString object.
Here is my drawing code:
data = calloc(POTHigh, POTWide * 2);
colorSpace = CGColorSpaceCreateDeviceGray();
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, colorSpace, kCGImageAlphaNone);
CGColorSpaceRelease(colorSpace);
if( ! context )
{
free(data);
[self release];
return nil;
}
UIGraphicsPushContext(context);
CGContextTranslateCTM(context, 0.0f, POTHigh);
CGContextScaleCTM(context, 1.0f, -1.0f);
// draw attributed string to context
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0.f, 0.f, dimensions.width, dimensions.height));
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
CTFrameDraw(frame, context);
UIGraphicsPopContext();
CFRelease(frame);
CGPathRelease(path);
CFRelease(frameSetter);
And now I have few troubles:
The first one - my texture is shown flipped vertically. I thought, that these lines
CGContextTranslateCTM(context, 0.0f, POTHigh);
CGContextScaleCTM(context, 1.0f, -1.0f);
should prevent this.
The second one, if I create RGB context, I cannot see anything on the screen. I tried to create RGB context with these lines.
colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
I tried to google, but don't find anything related to my issues =( Any help(links or suggestions) is appreciated.
Couple things to try:
Your data allocation isn't big enough for RGB. Try: data = calloc(POTHigh, POTWide * 4); for RGB color space.
CTFrameDraw draws in relation to GL coords so you don't need to use CGContextScaleCTM(context, 1.0f, -1.0f);
that line was put in the original CCTexture2D creation for a CCLabelTTF because it used NSString's drawInRect: which draws in relation to UIKit coords.
Maybe try other alpha mask flags...? Check out Apple's documentation on Supported Pixel Formats for iOS to see what your options are.
You may want to take a look at ActiveTextView-iOS (https://github.com/storify/ActiveTextView-iOS). It may be of use.
use this to get color texture:
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, colorSpace, kCGImageAlphaPremultipliedLast);

How do I fill color space in a CGrect

I am using the code below and am trying everything to color the resulting circle that it draws, but cannot for the life of me figure it out! Can anyone help? How do I color the circle in that my method draws?
What I have so far is this:
-(void)drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
CGContextStrokePath(context);
UIGraphicsPopContext();
}
- (void)drawRect:(CGRect)rect
{
CGPoint midPoint;
midPoint.x = self.bounds.origin.x + self.bounds.size.width/2;
midPoint.y = self.bounds.origin.y + self.bounds.size.width/2;
CGFloat size = self.bounds.size.width/2;
if (self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height/2;
size *= 0.90;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 10.0);
[[UIColor blackColor] setStroke];
CGColorRef color = [[UIColor redColor] CGColor];
CGContextSetFillColorWithColor(context, color);
CGContextFillPath(context);
[self drawCircleAtPoint:midPoint withRadius:size inContext:context];
}
You're trying to fill the current path, but you haven't added anything to it yet. The only point at which you add anything to the current path is in drawCircleAtPoint:withRadius:inContext:, after which you only stroke it.
Move your CGContextFillPath call into that method. You'll want to fill before you stroke, since the stroke will reset the current path. (If you want to fill on top of the inside of the stroke, you'll need to save the gstate before stroking and restore it after, so that the current path is still set when you fill.)