Nader Nader - 11 months ago 60
iOS Question

Calculating addCurveToPoint control points

I am using CoreGraphics to draw a rounded rectangle, I am familiar with the CG API ready made to draw the rounded rectangle, but I do not want to use it because the rectangle is not a fully-uniform rounded rectangle, part of it would be a rounded rectangle, the other parts would be a set of connected paths, for example, the top-left and top-right would be a rounded rectangle edges, however, the bottom edges are a group of connected Bezier paths.

My question is, if I want to draw the entire shape as Bezier path, how should I calculate the control points in addCurveToPoint for the corners? I know the radius and the coordinates of the points (based on radius too).


I have a sample code, I am trying to understand the math behind it:

UIBezierPath * rectangle = [UIBezierPath bezierPath];
[rectangle moveToPoint:CGPointMake(0, 8)];
[rectangle addCurveToPoint:CGPointMake(8.01, 0) controlPoint1:CGPointMake(0, 3.58) controlPoint2:CGPointMake(3.59, 0)];
[rectangle addLineToPoint:CGPointMake(208, 0)];
[rectangle addCurveToPoint:CGPointMake(224, 16.01) controlPoint1:CGPointMake(216.84, 0) controlPoint2:CGPointMake(224, 7.16)];
[rectangle addLineToPoint:CGPointMake(224, 175)];
[rectangle addCurveToPoint:CGPointMake(192, 207) controlPoint1:CGPointMake(224, 192.67) controlPoint2:CGPointMake(209.67, 207)];
[rectangle addLineToPoint:CGPointMake(64, 207)];
[rectangle addCurveToPoint:CGPointMake(0, 142.99) controlPoint1:CGPointMake(28.65, 207) controlPoint2:CGPointMake(0, 178.35)];
[rectangle addLineToPoint:CGPointMake(0, 8)];
[rectangle closePath];

The corners radius are 8, 16, 32 and 64 for top-left, top-right, bottom-right and bottom-left


Answer Source

I assume you want to add a 90 degree arc for the rounded corner. Use addArc instead of addCurveToPoint.

In Swift 3:

var path = UIBezierPath()


let center = CGPoint(x: topLeft.x + width - radius, y: topLeft.y)
path.addArc(withCenter: center, radius: radius, startAngle: CGFloat.pi, endAngle: CGFloat.pi * CGFloat(1.5), clockwise: true)

Of course, your parameters will vary.


Based on your code, it should look like this:

UIBezierPath * rectangle = [UIBezierPath bezierPath];
[rectangle moveToPoint:CGPointMake(0, 8)];
[rectangle addArcWithCenter:CGPointMake(8, 8) radius:8 startAngle:M_PI endAngle:M_PI*1.5 clockwise:YES];
[rectangle addLineToPoint:CGPointMake(208, 0)];
[rectangle addArcWithCenter:CGPointMake(208, 16) radius:16 startAngle:M_PI*1.5 endAngle:0 clockwise:YES];
[rectangle addLineToPoint:CGPointMake(224, 175)];
[rectangle addArcWithCenter:CGPointMake(208, 175) radius:32 startAngle:0 endAngle:M_PI*0.5 clockwise:YES];
[rectangle addLineToPoint:CGPointMake(64, 207)];
[rectangle addArcWithCenter:CGPointMake(64, 175) radius:64 startAngle:M_PI*0.5 endAngle:M_PI clockwise:YES];
[rectangle closePath];