Smooth curve between two points? - objective-c

I have two CGPoints. I need to draw a curve from one to the other. How can I draw it? Core graphics or Bezier path? If so, I need some guidance please. Thank you for your help in advance.

Use UIBezierPath or CGPath .
UIBezierPath works like NSBezierPath on OS X.
In your view's drawRect: method,
Declare the object
UIBezierPath *aPath = [UIBezierPath bezierPath];
Then start the first point.
[aPath moveToPoint: startPoint];
Next add a curved segment with control points.
This is the hard part figuring out where control points need to be.
There are two kinds.
Cubic curve
[aPath addCurveToPoint: aDestinationPoint controlPoint1: aControlPoint controlPoint2: anotherControlPoint];
Quadratic curve
[aPath addQuadCurveToPoint:aDestinationPoint controlPoint: aLonelyControlPoint];
Finally, call the set method on a UIColor (NSColor on Mac).
Then stroke or fill the path.
[aPath stroke];
You might also want to set the stroke width.
Remember drawing is back to front procedurally and if you want a different color call set on a different color before the next drawing command of fill or stroke
The CG version of events is similar but more convoluted.
http://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html

Related

IOS::How we can implement this [Curved Progress Bar]

I need to implement this functionality.Please suggest me.
It's not working properly means it is taking the end angle for the filling colour but here mentioned the "fromValue" and "toValue" but its not going through the fromValue and toValue.
Please anyone can edit my code.
Thanks in advance.
CAShapeLayer *circle=[CAShapeLayer layer];
circle.path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.img_View.frame.origin.x, self.img_View.frame.origin.y) radius:50 startAngle:0 endAngle:90 clockwise:YES].CGPath;
circle.fillColor=[UIColor clearColor].CGColor;
circle.strokeColor=[UIColor greenColor].CGColor;
circle.lineWidth=16;
CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.duration=10;
animation.removedOnCompletion=NO;
// animation.fromValue=#(0);
animation.fromValue=[NSNumber numberWithInt:0];
animation.toValue=[NSNumber numberWithInt:20];
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[circle addAnimation:animation forKey:#"drawCircleAnimation"];
[img_View.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
[img_View.layer addSublayer:circle];
you can do it with UIBezierPath it is very efficient to draw shapes.
The bezier path you use as a clip seems to be just a fraction of a circle, while in the image you show, the path is more complex : 2 fractions of a circle, linked by 2 lines, the whole path having a 'ring' shape.
This approach should work, I used it for a timer with the same kind of look. Although I didn't used directly AngleGradientLayer, I modified its - (CGImageRef)newImageGradientInRect:(CGRect)rect method to return a UIImage. But I had to rotate this image by + PI/2, as Pavlov gradient angular gradient starts horizontally.
I use a UIImage, because it's a background that DOESN'T change, so I saved an instance of this UIImage in my layer, and draw it whenever I update the clipping path
- (void)drawInContext:(CGContextRef)ctx {
UIBezierPath *currentPath = [self timerPath];
// other drawing code for glow (shadow) and white stroke)
CGContextAddPath(ctx, currentPath.CGPath);
// clip !
CGContextClip(ctx);
CGContextDrawImage(ctx, self.bounds, _circularGradientImage.CGImage);
//_circularGradientImage from modified newImageGradientInRect method.
}

NSBezierPath drawing

I want to do a rounded rectangle outline on an NSImage and I figured that using NSBezierPath would be the best way. However, I ran into a problem: instead of drawing a nice curve, I get this:
For reasons I can't understand, NSBezierPath is drawing the rounded part with a darker color than the rest.
Here's the code I'm using (inside a drawRect: call on a custom view):
NSBezierPath* bp = [NSBezierPath bezierPathWithRoundedRect: self.bounds xRadius: 5 yRadius: 5];
[[[NSColor blackColor] colorWithAlphaComponent: 0.5] setStroke];
[bp stroke];
Any ideas?
Edit:
If I inset the path by 0.5 everything draws just fine. But why is it that I get this when I offset the path by 10 pixels (for example)?
If I understand correctly, it should draw a thin line as well...
Many rendering systems are derived from the PostScript drawing model. Core Graphics is one of these derivative systems. (Here are some others: PDF, SVG, the HTML Canvas 2D Context, Cairo.)
All of these systems have the idea of stroking a path with a line of some fixed width. When you stroke the path, the line straddles the path: half of the line's width is on one side of the path, and half of the line's width is on the other side. Here's a diagram that may make this clearer:
Now, what happens when you stroke a path that lies along the boundary of your view? Half of the stroke falls outside of your view's bounds and is clipped away - not drawn. You only see the half of the stroke that falls inside the view's bounds.
When you use a rounded corner, that corner pulls away from the view's boundary, toward its center, so more of the stroke around the corner falls inside the view's boundary. So the stroke appears to get thicker around the rounded corner, like this:
To fix this, you need to inset your path by half the line width, so that the entire stroke falls inside your view's bounds along the entire path. The default line width is 1.0, so:
NSBezierPath* bp = [NSBezierPath bezierPathWithRoundedRect:
NSRectInset(self.bounds, 0.5, 0.5) xRadius:5 yRadius:5];
In iOS field, just minus the radius of the circle to prevent from being clipped.
UIBezierPath *roundPath = [UIBezierPath bezierPath];
[roundPath addArcWithCenter:
CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2)
radius:(self.frame.size.width / 2 - 0.5)
startAngle:M_PI_2 endAngle:M_PI * 3 / 2.f clockwise:YES];

UIBezierPath - Animating Fill

I have a UIBezierPath (a circle) built incrementally with:
[circlePath addArcWithCenter:clockCenter radius:radius startAngle:angleRadians endAngle:1.5*M_PI clockwise:YES];
...
[circlePath closePath];
[COLOR_CIRCLE setFill];
[circlePath fill];
Occasionally, I would like to animate the fill so that it takes a second to completely fill and follows the path as it was built (clockwise). What is the preferred method of accomplishing this? Right now I'm thinking Core Animation but I'm hoping there's a fill:withDelay or some such that I haven't stumbled upon. TIA.
You could try this:
Create a CAShapeLayer whose path is set to your shape. Use this CAShapeLayer as a mask for another layer into which you draw a filled arc/circle. Then animate the arc/circle arc angle from 0º to 360º. That might approximate the effect you want.
I can't find a "built-in" way to animate the fill as you want. There is a built-in way to animate the stroke, however:
Use a UIView with a CAShapeLayer backing it. CAShapeLayer has a path property. You can then apply an animation to the layer's strokeStart and/or strokeEnd properties.

Is UIBezierPath the best way to make a movable rounded rectangle?

I'm making a UISlider from scratch. I started by making a rounded rectangle, which I did using the code below:
CGRect frame = CGRectMake(10, 10, self.frame.size.width, 10);
UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:10.0];
[[UIColor blueColor] setFill];
[path fill];
I saw some other options to make a rounded rectangle but thought this was the quickest way. Are there any limitations with making one using UIBezierPath? Namely, the slider needs to be able to move upon touch events, so I want to change the center property of a BezierPath. Is this possible?
You would need to either recreate the bezier path each time you need to change the slider position, or use CGContext's transform matrix to draw it in a different place.
I suggest you look at using a CALayer for the moving part of the slider. Draw the channel of the slider in view.layer, and add a sublayer in which you draw the "thumb" of the slider. Then you can just reposition the thumb layer when you need to move it.

Drawing a sketchy-looking line, programmatically

I would like to know if you guys have any idea of how I could possibly draw a sketchy-looking line on an iOS app.
Currently I am drawing thanks to a UIBezierPath which I then render into a bitmap graphics context. How could I make the line look sketchy?
// Produce and add points to draw in the UIBezierPath
// Draw the path into the Bitmap context
UIGraphicsBeginImageContext(self.bounds.size);
[frameBuffer drawAtPoint:CGPointMake(0, 0) blendMode:kCGBlendModeCopy alpha:1.0];
[[datasource lineStrokeColorForSketchCanvas:self] setStroke];
[curvePath stroke];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Thank ou very much in advance :)
I would suggest using a small batch of "sketchy" line textures, and then using those + the UIBezierPath to place the sketchy images along the path at the correct rotation.
You could draw those to the context, and save them so that you don't have to generate them every single time.
Elaboration:
Start at one end of your UIBezierPath, every x points down the path, draw a sketchy line section centered on that point, keep going until you get to the end of the path.