iPhone Pixel Coordinate Issue - ios

I am trying to make a line graph using the drawRect method but I have came across a major problem. The 0 point on the iPhone screen is in the top left corner. Is there any way to either relocate the 0,0 point or change the coordinates input to where they would be if the 0,0 point was in the bottom left corner?
Heres My drawRect method
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
//Coordinates of bottom left corner (480 went off screen)
CGContextMoveToPoint(context, 0, 460);
CGContextAddLineToPoint(context, 320, 0);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}

This page describes how to treat it as a right-hand coordinate system instead of a left-hand, which sounds like what you want

Related

How can I draw a line with gradually change edge using CoreGraphics?

I want to accomplish a function just like a Brush. The area where finger swipes changes to trasparent with gradually changed border.
I can only change the color to crystal clear now with following codes:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.eraser) return;
CGFloat scale = self.transform.a;
if (scale < 1) scale = 1;
CGPoint p = [[touches anyObject] locationInView: self];
CGPoint q = [[touches anyObject] previousLocationInView: self];
UIImage* image;
image = self.image;
CGSize size = self.frame.size;
UIGraphicsBeginImageContext(size);
CGRect rect;
rect.origin = CGPointZero;
rect.size = size;
[image drawInRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextBeginPath(context);
CGContextSaveGState( context );
CGContextSetLineWidth(context, (10.0 / scale) + 1);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextMoveToPoint(context, q.x, q.y);
CGContextAddLineToPoint(context, p.x, p.y);
CGContextStrokePath(context);
CGContextRestoreGState( context );
UIImage* editedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBounds:rect];
[self setImage:editedImage];
}
How can I get the edge with gradually change? Thanks in advance.
You can achieve this effect by drawing a radial gradient with a variable alpha in the kCGBlendModeDestinationIn mode in each spot the user passes.
This blend mode has the effect of only applying the layer's alpha to layers below. With the variable alpha of our gradient, we can achieve this effect.
const CGFloat kBrushSize = 10.f;
CGContextSaveGState(context);
// Make a radial gradient that goes from transparent black on the inside
// to opaque back on the outside.
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0 };
CGColorSpaceRef myColorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGGradientRef myGradient = CGGradientCreateWithColorComponents (myColorspace, components,
locations, num_locations);
CGColorSpaceRelease(myColorspace);
// Draw the gradient at the point using kCGBlendModeDestinationIn
// This mode only applies the new layer's alpha to the lower layer.
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawRadialGradient(context, myGradient, p, 0.f, p, (kBrushSize / scale) + 1, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(myGradient);
CGContextRestoreGState(context);
Here is a screenshot of this code in action:
Note: Using this technique, if the user is moving his/her finger very fast, you may see a spacing effect where discrete brush dots are visible. This is a feature of some graphics software, but if this is undesirable for you, you can add code to interpolate the points between the current and last to draw more brush points, creating a more continuous stroke.
Also, you should be able to adjust the gradient color stops to achieve any kind of brush softness you like.
Source: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/dq_shadings.html

iOS - 2D line drawing on negative coordinates

I am developing an app in which user can draw lines. The desktop version of the same app is able to draw lines on negative coordinates and I would like to have same capability in iOS app too.
What I've tried so far:-
I have a UIViewController inside which I have overridden - (void)drawRect:(CGRect)rect and drawn the line. Here is the code I am using:-
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, self.bounds);
CGPoint startPoint = CGPointMake(self.startHandle.frame.origin.x + self.startHandle.frame.size.width/2, self.startHandle.frame.origin.y + self.startHandle.frame.size.height/2);
CGPoint endPoint = CGPointMake(self.endHandle.frame.origin.x + self.endHandle.frame.size.width/2, self.endHandle.frame.origin.y + self.endHandle.frame.size.height/2);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, 2.0f);
CGContextMoveToPoint(context, startPoint.x, startPoint.y ); //start at this point
CGContextAddLineToPoint(context, endPoint.x, endPoint.y); //draw to this point
It works very well until I have startPoint.x as a negative value. With negative value, I don't see the portion of line that is behind 0,0 coordinates. Any help or information is appreciated.
Following on from what #matt said (he has since deleted his answer, shame as it was still useful), you simply want to apply a transform to the context in order to draw in a standard cartesian coordinate system, where (0,0) is the center of the screen.
The context provided to you from within drawRect has its origin at the top left of the screen, with the positive y-direction going down the screen.
So first, we'll want to first flip the y-axis so that the positive y-direction goes up the screen.
We can do this by using CGContextScaleCTM(context, 1, -1). This will reflect the y-axis of the context. Therefore, this reflected context will have a y-axis where the positive direction goes up the screen.
Next, we want to translate the context to the correct position, so that (0,0) corresponds to the center of the screen. We should therefore shift the y-axis down by half of the height (so that 0 on the y-axis is now at the center), and the x-axis to the right by half of the width.
We can do this by using CGContextTranslateCTM(context, width*0.5, -height*0.5), where width and height are the width and height of your view respectively.
Now your context coordinates will look like this:
You could implement this into your drawRect like so:
-(void) drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat width = self.bounds.size.width;
CGFloat height = self.bounds.size.height;
// scale and translate to the standard cartesian coordinate system where the (0,0) is the center of the screen.
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, width*0.5, -height*0.5);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextSetLineWidth(ctx, 2.0);
// add y-axis
CGContextMoveToPoint(ctx, 0, -height*0.5);
CGContextAddLineToPoint(ctx, 0, height*0.5);
// add x-axis
CGContextMoveToPoint(ctx, -width*0.5, 0);
CGContextAddLineToPoint(ctx, width*0.5, 0);
// stroke axis
CGContextStrokePath(ctx);
// define start and end points
CGPoint startPoint = CGPointMake(-100, 100);
CGPoint endPoint = CGPointMake(100, -200);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextSetLineWidth(ctx, 5.0);
CGContextMoveToPoint(ctx, startPoint.x, startPoint.y );
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
CGContextStrokePath(ctx);
}
This will give the following output:
I added the red lines to represent the y and x axis, in order to clarify what we've done here.
CGContextClearRect(context, self.bounds);
You can draw out of this bounds,please make a larger rect.

cgcontext drawing - first set of shape is shown, the second exact same set, shifted slightly right is not shown

I have the following code:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// Left frame.
CGContextAddRect(context, CGRectMake(0, 0,
frameWidth,
self.frameHeight));
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:frameBorderColorRed
green:frameBorderColorGreen
blue:frameBorderColorBlue
alpha:frameBorderColorAlpha].CGColor);
CGContextFillPath(context);
CGContextAddRect(context, CGRectMake(frameBorderWidth,
frameBorderWidth,
frameWidth - (2*frameBorderWidth),
self.frameHeight - (2*frameBorderWidth)));
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillPath(context);
// Right frame.
CGContextAddRect(context, CGRectMake(frameWidth + distanceBetweenFrames,
0,
frameWidth,
self.frameHeight));
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:frameBorderColorRed
green:frameBorderColorGreen
blue:frameBorderColorBlue
alpha:frameBorderColorAlpha].CGColor);
CGContextFillPath(context);
CGContextAddRect(context, CGRectMake(frameWidth + distanceBetweenFrames + frameBorderWidth,
frameBorderWidth,
frameWidth - (2*frameBorderWidth),
self.frameHeight - (2*frameBorderWidth)));
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillPath(context);
}
The left frame is showing but the right frame isn't. However, if I were to comment out the left frame, the right frame shows. I have also tried drawing the lines themselves as in the docs:
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGContext/index.html#//apple_ref/c/func/CGContextAddRect
To no avail.
I would consider using CoreAnimation since it uses GPU.
Besides the problem is that you close current path by:
CGContextFillPath(context);
and then try to use:
CGContextAddRect
As documentation says: "Adds a rectangular path to the current path."
You need to use method below to add another path:
CGContextMoveToPoint
More detailed information you can read there:
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGContext/index.html

Filling ellipse disappears other graphics elements

I am trying to draw some graphics elements in a UIView inside drawRect method. Code is attached, when I run this code the circle filled with color makes other line disappear.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, x, y);
CGRect rectangle = CGRectMake(60+x,100+y,100,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextFillEllipseInRect(context, rectangle);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
Please help
Having the same problem. Closer look at documentation on CGContextFillEllipseInRect function has totally disappointed me:
Discussion
As a side effect when you call this function, Quartz clears the
current path
https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGContext/Reference/reference.html#//apple_ref/c/func/CGContextFillEllipseInRect

CGContextRef inset?

So, I have this code, that draws a circle with a line around it.
- (void)drawRect:(CGRect)rect
{
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(contextRef, 40.0);
CGContextSetRGBFillColor(contextRef, 0.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(contextRef, 132.0/255.0, 128.0/255.0, 128.0/255.0, 1.0);
CGContextFillEllipseInRect(contextRef, rect);
CGContextStrokeEllipseInRect(contextRef, rect);
}
The problem is that half of the width of the line falls outside the rect.
So, what I would like to do, is to create an inset relative to the line width, to compensate for this.
Or maybe there is a method, that tells my line to remain inside the boundaries of the circle?
Before filling,
rect = CGRectInset(rect, 1, 1);

Resources